nektos/act · warning

Failed to parse: %s

Error message

Failed to parse: %s

What it means

Thrown when an expression references the 'jobs' context but impl.env.Jobs is nil. act only populates the jobs context in specific positions (outputs of reusable-workflow callers / workflow-level expressions); elsewhere it is unavailable and this error fires instead of returning empty data.

Source

Thrown at pkg/exprparser/interpreter.go:89

	config Config
}

func NewInterpeter(env *EvaluationEnvironment, config Config) Interpreter {
	return &interperterImpl{
		env:    env,
		config: config,
	}
}

func (impl *interperterImpl) Evaluate(input string, defaultStatusCheck DefaultStatusCheck) (interface{}, error) {
	input = strings.TrimPrefix(input, "${{")
	if defaultStatusCheck != DefaultStatusCheckNone && input == "" {
		input = "success()"
	}
	parser := actionlint.NewExprParser()
	exprNode, err := parser.Parse(actionlint.NewExprLexer(input + "}}"))
	if err != nil {
		return nil, fmt.Errorf("Failed to parse: %s", err.Message)
	}

	if defaultStatusCheck != DefaultStatusCheckNone {
		hasStatusCheckFunction := false
		actionlint.VisitExprNode(exprNode, func(node, _ actionlint.ExprNode, entering bool) {
			if funcCallNode, ok := node.(*actionlint.FuncCallNode); entering && ok {
				switch strings.ToLower(funcCallNode.Callee) {
				case "success", "always", "cancelled", "failure":
					hasStatusCheckFunction = true
				}
			}
		})

		if !hasStatusCheckFunction {
			exprNode = &actionlint.LogicalOpNode{
				Kind: actionlint.LogicalOpNodeKindAnd,
				Left: &actionlint.FuncCallNode{
					Callee: defaultStatusCheck.String(),

View on GitHub (pinned to 4f41128141)

Solutions

  1. Access jobs.* only where GitHub documents it (workflow-level outputs wiring, caller-side expressions).
  2. Pass values explicitly via outputs/inputs instead of reading the jobs context downstream.
  3. Update act — jobs-context support for reusable workflows has improved across versions.
  4. If unsupported in act, guard with a contains-style check or move logic to the caller workflow.

Example fix

# before (inside reusable workflow step)
run: echo ${{ jobs.build.outputs.img }}
# after (wire through outputs)
jobs:
  build:
    outputs:
      img: ${{ steps.b.out }}
  call:
    uses: ./.github/workflows/child.yml
Defensive patterns

Strategy: validation

Validate before calling

func jobsContextAvailable(env *exprparser.ExpressionEnvLoading) bool {
  return env.Jobs != nil // mirror the interpreter's own nil check
}

Try / catch

if v, err := interp.Evaluate('${{ jobs.build.result }}', 0); err != nil {
  if strings.Contains(err.Error(), 'Unavailable context: jobs') {
    v = 'skipped' // not a caller-side evaluation: use a default
  } else { return err }
}

Prevention

When it happens

Trigger: Using jobs.<id>.outputs or jobs.<id>.result in a place act does not support (e.g. inside a reusable workflow's own steps, or a run where the jobs env was never wired up); referencing jobs in a locally triggered event that GitHub itself would not populate it for.

Common situations: Reusable workflows evaluated locally with act; expressions valid on github.com but hitting act's unsupported paths; typo'd context names that fall through to the generic unavailable-context case only when spelled 'jobs'.

Understand the failure class

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/9457894eba529335. Report an issue: GitHub.