nektos/act · error

missing steps in composite action

Error message

missing steps in composite action

What it means

execAsComposite (pkg/runner/action_composite.go) runs the composite action's main steps. It calls step.getCompositeRunContext(ctx) then step.getCompositeSteps(); if steps is nil or steps.main is nil it errors, because a composite action with no main steps cannot execute. steps is populated from the action model's Runs.Steps — so this means the loaded action.yml has 'using: composite' but no (or unparsable) 'runs.steps'.

Source

Thrown at pkg/runner/action_composite.go:94

		EventJSON:        parent.EventJSON,
		nodeToolFullPath: parent.nodeToolFullPath,
	}
	compositerc.ExprEval = compositerc.NewExpressionEvaluator(ctx)

	return compositerc
}

func execAsComposite(step actionStep) common.Executor {
	rc := step.getRunContext()
	action := step.getActionModel()

	return func(ctx context.Context) error {
		compositeRC := step.getCompositeRunContext(ctx)

		steps := step.getCompositeSteps()

		if steps == nil || steps.main == nil {
			return fmt.Errorf("missing steps in composite action")
		}

		ctx = WithCompositeLogger(ctx, &compositeRC.Masks)

		err := steps.main(ctx)

		// Map outputs from composite RunContext to job RunContext
		eval := compositeRC.NewExpressionEvaluator(ctx)
		for outputName, output := range action.Outputs {
			rc.setOutput(ctx, map[string]string{
				"name": outputName,
			}, eval.Interpolate(ctx, output.Value))
		}

		rc.Masks = append(rc.Masks, compositeRC.Masks...)
		rc.ExtraPath = compositeRC.ExtraPath
		// compositeRC.Env is dirty, contains INPUT_ and merged step env, only rely on compositeRC.GlobalEnv
		mergeIntoMap := mergeIntoMapCaseSensitive

View on GitHub (pinned to 4f41128141)

Solutions

  1. Add a non-empty 'steps:' list under 'runs:' in the composite action's action.yml.
  2. Validate YAML structure: 'runs' must contain 'using: composite' and 'steps:' as a list of step objects.
  3. Verify the local 'uses:' path resolves to the directory holding action.yml.
  4. Clear cache for remote actions and re-fetch at a ref where the action.yml is correct.

Example fix

# before (action.yml)
name: my-action
runs:
  using: composite

# after
name: my-action
runs:
  using: composite
  steps:
    - run: echo hi
      shell: bash
Defensive patterns

Strategy: validation

Validate before calling

python3 - <<'EOF'
import yaml,sys
a=yaml.safe_load(open('action.yml'))
runs=a.get('runs',{})
assert runs.get('using')=='composite', 'not composite'
assert isinstance(runs.get('steps'),list) and runs['steps'], 'runs.steps missing/empty'
print('composite action.yml ok')
EOF

Prevention

When it happens

Trigger: action.yml contains 'runs: using: composite' with a missing or empty 'steps:' key; steps failed to unmarshal (wrong indentation, non-list value); or the action model was loaded from an empty/incorrect file at the action path.

Common situations: Hand-written action.yml that forgets 'steps:' under 'runs:'; copy-paste from a Docker action leaving 'image:' but no composite steps; local action directory path wrong so an unrelated/blank action.yml is read.

Related errors


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