micro/go-micro · error
flow: step %q has no Run function
Error message
flow: step %q has no Run function
What it means
Every Step in a flow must provide a Run StepFunc; a nil Run is treated as a configuration error rather than a no-op. runStep checks for this before executing and fails the step immediately with the step's name in the message. This catches flows built by leaving the Run field unset, since the library cannot infer the step's action.
Source
Thrown at flow/steps.go:646
return run, err
}
if f.opts.DeleteOnSuccess && f.checkpoint != nil {
if err := f.checkpoint.Delete(ctx, run.ID); err != nil {
spanErr = err
return run, err
}
}
f.record(resultFromRun(f.opts.TriggerTopic, run))
f.log.Logf(logger.InfoLevel, "Flow %s run %s completed (%d steps)", f.name, run.ID, len(steps))
return run, nil
}
// runStep runs one step, retrying on error up to the resolved retry count.
// A step with no Run function is a configuration error, and a canceled run
// stops retrying immediately rather than burning the rest of its budget.
func (f *Flow) runStep(ctx context.Context, step Step, in State) (State, int, Verification, error) {
if step.Run == nil {
return in, 0, Verification{}, fmt.Errorf("flow: step %q has no Run function", step.Name)
}
retries := f.opts.Retry
if step.Retry > 0 {
retries = step.Retry
}
var lastErr error
var lastVerification Verification
var feedback string
for attempt := 1; attempt <= retries+1; attempt++ {
// Stop the moment the run's context is canceled or its deadline
// passes — a canceled run shouldn't keep retrying, and the context
// error is surfaced so callers can detect cancellation upstream.
if err := ctx.Err(); err != nil {
return in, attempt - 1, lastVerification, err
}
attemptCtx := ctx
if info, ok := ai.RunInfoFrom(ctx); ok {
info.Step = step.NameView on GitHub (pinned to 24529f1404)
Solutions
- Set a Run function on every Step: Run: func(ctx context.Context, in flow.State) (flow.State, error) {...} or use a helper like flow.Call/flow.LLM.
- Validate steps at startup: iterate your steps and fail fast if any has a nil Run before creating the flow.
- Check helper functions for paths that return a nil StepFunc (e.g. when config is missing) and return an error or a default step instead.
- If the step was a placeholder, remove it from the Steps slice.
Example fix
// before
steps := []flow.Step{{Name: "enrich"}} // Run missing
// after
steps := []flow.Step{{Name: "enrich", Run: func(ctx context.Context, in flow.State) (flow.State, error) {
return in, nil // real work here
}}} Defensive patterns
Strategy: validation
Validate before calling
for i, s := range steps {
if s.Run == nil {
return fmt.Errorf("step %d (%q) has no Run function", i, s.Name)
}
} Type guard
func stepRunnable(s flow.Step) bool { return s.Run != nil } Try / catch
if _, _, err := f.runStep(ctx, step, in); err != nil {
if strings.Contains(err.Error(), "has no Run function") {
// configuration bug: fix the step definition, do not retry
return fmt.Errorf("misconfigured flow: %w", err)
}
// genuine step failure: retry path applies
} Prevention
- Validate all steps (non-nil Run) in a unit test over your step slice
- Use flow.Call/LLM/Agent helpers instead of hand-built Step literals where possible
- Check helper functions never return a nil StepFunc on error paths
- Run validateSteps at service startup to fail fast on bad definitions
When it happens
Trigger: Constructing flow.Step{Name: "x"} (or a step struct literal) without setting Run, then starting or resuming the flow; or a helper returning a nil StepFunc assigned into a Step.
Common situations: Copy-pasted step definitions where the Run field was accidentally deleted; refactoring steps into a shared slice where some placeholders have nil Run; conditional step construction where a helper returned nil on some code path; JSON/YAML-driven step config that can't express function values.
Related errors
- flow: step %d has an empty name
- ai model is nil
- LLM step requires a flow model (set Provider/APIKey)
- flow %s has no checkpoint configured
- flow: duplicate step name %q
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/1d0f5233d9a5aa84.
Report an issue: GitHub.