Skip to content

engine.env: non-string values (numbers/booleans) are silently dropped at compile time #39462

Description

@yskopets

🤖 This issue has been generated by Claude Code.

Summary

When an engine.env value in workflow frontmatter is a non-string YAML scalar (a number or a boolean), gh aw compile silently drops it from the generated *.lock.yml. No warning, no error — the variable simply never appears in the Execute ... CLI step's env: block. Only string-typed values survive.

This is surprising because GitHub Actions workflow syntax does allow numbers and booleans as env values (it coerces them to strings at runtime), so the input looks perfectly valid to the author.

Version: v0.79.1.

Reproduction

Minimal workflow:

---
engine:
  id: claude
  env:
    # string values — kept
    OTEL_TRACES_EXPORTER: console,otlp
    # numeric values — silently dropped
    CLAUDE_CODE_ENABLE_TELEMETRY: 1
    OTEL_TRACES_EXPORT_INTERVAL: 1000
    OTEL_LOG_USER_PROMPTS: 1
    # boolean values — also dropped
    SOME_FLAG: true
---

# Test
hello

Run gh aw compile and inspect the env: of the Execute ... step in the generated *.lock.yml.

Expected

All five variables present (numbers/booleans rendered as strings), matching how GitHub Actions itself treats them.

Actual

Only OTEL_TRACES_EXPORTER is emitted. CLAUDE_CODE_ENABLE_TELEMETRY, OTEL_TRACES_EXPORT_INTERVAL, OTEL_LOG_USER_PROMPTS, and SOME_FLAG are gone — with no diagnostic output.

Quoting the values (CLAUDE_CODE_ENABLE_TELEMETRY: "1", SOME_FLAG: "true") makes them reappear, which is the only hint that anything was wrong.

Root cause

pkg/workflow/engine.go, in ExtractEngineConfig (the env extraction block, ~lines 375–385 in v0.79.1):

// Extract optional 'env' field (object/map of strings)
if env, hasEnv := engineObj["env"]; hasEnv {
    if envMap, ok := env.(map[string]any); ok {
        config.Env = make(map[string]string)
        for key, value := range envMap {
            if valueStr, ok := value.(string); ok { // non-string → skipped, silently
                config.Env[key] = valueStr
            }
        }
    }
}

The value.(string) type assertion fails for YAML-parsed integers (int/float64) and booleans (bool), and the else branch does nothing — so those entries are discarded with no record that they existed.

Why the input is valid

The official GitHub Actions workflow JSON schema (SchemaStore github-workflow.json, used by GitHub's own validation) defines env values as:

"additionalProperties": { "oneOf": [ {"type": "string"}, {"type": "number"}, {"type": "boolean"} ] }

So FOO: 1 and FOO: true are legal workflow input; GitHub coerces them to "1" / "true". gh-aw rejecting them — and doing so silently — is the mismatch.

Request

Either of the following would resolve the trap; the first is preferable:

  1. Support non-string scalars — coerce numbers and booleans to their string form during extraction (e.g. fmt.Sprintf("%v", value) for string/int/int64/float64/bool), matching GitHub Actions semantics.
  2. Fail at compile time — if non-string coercion isn't desired, emit a clear compile error (or at minimum a warning) naming the offending key, instead of silently dropping it.

The current silent-drop behavior is the worst of both: valid-looking input produces a compiled workflow that's missing configuration, with nothing pointing at the cause.

Happy to send a PR for option 1 if that's the preferred direction.

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions