micro/go-micro · error

run %s is waiting at unknown step %q

Error message

run %s is waiting at unknown step %q

What it means

ResumeWith resumes a run waiting for input by marking the awaited step done and advancing. If the run's persisted State.Stage doesn't match any step in the flow's current Steps configuration (stepIndex < 0), the library cannot identify which step the input satisfies and returns this error. It almost always means the flow definition and the persisted run state have drifted apart.

Source

Thrown at flow/steps.go:529

		return err
	}
	if f.checkpoint == nil {
		return fmt.Errorf("flow %s has no checkpoint configured", f.name)
	}
	run, ok, err := f.checkpoint.Load(ctx, runID)
	if err != nil {
		return err
	}
	if !ok {
		return fmt.Errorf("run %s not found", runID)
	}
	if run.Status != "waiting" {
		return fmt.Errorf("run %s is not waiting for input (status %q)", runID, run.Status)
	}
	steps := f.opts.Steps
	i := stepIndex(steps, run.State.Stage)
	if i < 0 {
		return fmt.Errorf("run %s is waiting at unknown step %q", runID, run.State.Stage)
	}
	// The awaited step is satisfied by the injected input; record it done and
	// advance so runFrom re-enters at the next step.
	run.Steps[i].Status = "done"
	run.Steps[i].Result = truncate(input, 200)
	run.State.Data = []byte(input)
	if i+1 < len(steps) {
		run.State.Stage = steps[i+1].Name
	} else {
		run.State.Stage = ""
	}
	run.Await = nil
	run.Status = "running"
	_, err = f.runFrom(ctx, run)
	return err
}

// runFrom executes steps from the run's current Stage to the end,

View on GitHub (pinned to 24529f1404)

Solutions

  1. Restore the persisted step name in the flow's Steps so State.Stage matches again.
  2. Migrate the stale run: update run.State.Stage in the checkpoint store to a valid step name, or expire the run.
  3. Version flows (distinct flow names/checkpoint keys per definition version) so old runs resume against their matching definition.
  4. Drain all waiting runs via ResumeWith before deploying step renames or deletions.

Example fix

// before (deployed rename)
flow.Steps(flow.Step{Name: "review-v2", Run: review}) // runs wait at "review"

// after (keep original name)
flow.Steps(flow.Step{Name: "review", Run: review})
Defensive patterns

Strategy: validation

Validate before calling

run, _, err := ckpt.Load(ctx, runID)
if err == nil && stepIndex(f.opts.Steps, run.State.Stage) < 0 {
    return fmt.Errorf("run %s waits at unknown step %q; cannot inject input", runID, run.State.Stage)
}

Type guard

func stageKnown(steps []flow.Step, stage string) bool { return stepIndex(steps, stage) >= 0 }

Try / catch

if _, err := f.ResumeWith(ctx, runID, input); err != nil {
    if strings.Contains(err.Error(), "waiting at unknown step") {
        // stale run from an old flow definition; expire or migrate it
        return expireRun(ctx, runID)
    }
    return err
}

Prevention

When it happens

Trigger: Calling flow.ResumeWith(ctx, runID, input) where run.State.Stage names a step absent from f.opts.Steps — the step was renamed/removed in a deploy, or the run was created by a differently configured flow sharing the same checkpoint store.

Common situations: Deploying a new flow version with renamed steps while waiting runs persist across restarts; resuming a run with a different Flow instance than the one that started it; multiple flow definitions writing to one checkpoint store without namespacing.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/c73aa267cd95a6d2. Report an issue: GitHub.