nektos/act · error
invalid Step %v: missing run or uses key
Error message
invalid Step %v: missing run or uses key
What it means
In the job executor's step-building loop (pkg/runner/job_executor.go), act iterates infoSteps produced by splitting each step's 'run'/'uses' interpolation. If a step model comes back nil, the step had neither a 'run:' nor a 'uses:' key after parsing — the executor factory inserted a nil placeholder — and this error names the offending step index.
Source
Thrown at pkg/runner/job_executor.go:69
rc.Env[k] = rc.ExprEval.Interpolate(ctx, v)
}
return nil
})
var setJobError = func(ctx context.Context, err error) error {
if err == nil {
return nil
}
logger := common.Logger(ctx)
logger.Errorf("%v", err)
common.SetJobError(ctx, err)
return err
}
for i, stepModel := range infoSteps {
if stepModel == nil {
return func(_ context.Context) error {
return fmt.Errorf("invalid Step %v: missing run or uses key", i)
}
}
if stepModel.ID == "" {
stepModel.ID = fmt.Sprintf("%d", i)
}
step, err := sf.newStep(stepModel, rc)
if err != nil {
return common.NewErrorExecutor(err)
}
preSteps = append(preSteps, useStepLogger(rc, stepModel, stepStagePre, step.pre().ThenError(setJobError)))
stepExec := step.main()
steps = append(steps, useStepLogger(rc, stepModel, stepStageMain, func(ctx context.Context) error {
err := stepExec(ctx)
if err != nil {View on GitHub (pinned to 4f41128141)
Solutions
- Go to the job's steps list; the failing step is at the printed index (0-based). Add a valid 'run:' or 'uses:' to it, or delete the step.
- Run yamllint/actionlint on the workflow to catch structure errors.
- Check indentation: 'run'/'uses' must be direct children of the step map item.
Example fix
# before
steps:
- name: build
if: always()
# after
steps:
- name: build
if: always()
run: make build Defensive patterns
Strategy: validation
Validate before calling
python3 - <<'EOF'
import yaml,glob
for f in glob.glob('.github/workflows/*.y*ml'):
y=yaml.safe_load(open(f))
for jid,job in (y.get('jobs') or {}).items():
for i,s in enumerate(job.get('steps') or []):
if s is None or not ('run' in s or 'uses' in s):
raise SystemExit(f'{f}: job {jid} step index {i} has no run/uses key')
print('steps ok')
EOF Prevention
- Run actionlint in CI; it flags steps without run/uses.
- The error's index is 0-based — count steps from zero to find the offender.
- Watch YAML indentation when editing steps.
When it happens
Trigger: A workflow job step that has neither 'run' nor 'uses' (e.g. only 'name:' and 'if:'), or a step whose keys are misindented so the parser sees an empty step entry. The index i is the 0-based position in the job's steps list.
Common situations: Copy-paste where the 'run:' line was deleted; YAML indentation making 'run' a child of another key; placeholder/commented-out step bodies.
Related errors
- ErrShortRef
- unable to read workflow '%s': file is empty: %w
- workflow is not valid. '%s': %w
- Actions YAML Schema Validation Error detected:\nFor more inf
- missing steps in composite action
AI-assisted analysis of nektos/act@4f41128141 (2026-08-15).
Data as JSON: /api/errors/7a59504d0ed47e48.
Report an issue: GitHub.