micro/go-micro · error

agent run %s is not waiting for human input

Error message

agent run %s is not waiting for human input

What it means

agent.ResumeInput requires the checkpointed run to be paused specifically at the "input-required" stage (Status=="paused" && State.Stage==agentInputStep). Any other state — running, done, approval-paused, failed — is rejected because supplying human input is meaningless or unsafe there.

Source

Thrown at agent/checkpoint.go:139

	if !ok {
		return nil, fmt.Errorf("agent resume input: unsupported agent implementation %T", ag)
	}
	return a.resumeInput(ctx, runID, input)
}

func (a *agentImpl) resumeInput(ctx context.Context, runID, input string) (*Response, error) {
	if a.opts.Checkpoint == nil {
		return nil, fmt.Errorf("agent %s has no checkpoint configured", a.opts.Name)
	}
	run, ok, err := a.opts.Checkpoint.Load(ctx, runID)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, fmt.Errorf("agent run %s not found", runID)
	}
	if run.Status != "paused" || run.State.Stage != agentInputStep {
		return nil, fmt.Errorf("agent run %s is not waiting for human input", runID)
	}
	var p inputPause
	if err := run.State.Scan(&p); err != nil {
		return nil, fmt.Errorf("agent run %s input state decode: %w", runID, err)
	}
	message := p.OriginalMessage
	if message == "" {
		message = string(run.State.Data)
	}
	message += "\n\nHuman input: " + input
	run.Status = "running"
	run.State.Stage = agentAskStep
	run.State.Data = []byte(message)
	a.mu.Lock()
	defer a.mu.Unlock()
	if a.model == nil {
		a.setup()
	}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Check the run's status and stage via the checkpoint store before calling ResumeInput and route to Resume/other handling as appropriate.
  2. Make input answering idempotent/single-shot: mark the prompt as answered in your own system before invoking ResumeInput.
  3. Use Resume for approval-paused runs; only the request_input tool flow needs ResumeInput.
  4. Handle the error as a benign race in concurrent workers and let one caller proceed.

Example fix

// before
agent.ResumeInput(ctx, ag, runID, input) // run already running after first call
// after
run, ok, _ := ckpt.Load(ctx, runID)
if ok && run.Status == "paused" && run.State.Stage == "input-required" {
    _, err = agent.ResumeInput(ctx, ag, runID, input)
}
Defensive patterns

Strategy: validation

Validate before calling

run, ok, _ := ckpt.Load(ctx, runID)
if !ok || run.Status != "paused" || run.State.Stage != "input-required" {
    return fmt.Errorf("run %s not awaiting input (status=%s stage=%s)", runID, run.Status, run.State.Stage)
}

Type guard

func awaitingInput(r flow.Run) bool {
    return r.Status == "paused" && r.State.Stage == "input-required"
}

Try / catch

_, err := agent.ResumeInput(ctx, ag, runID, input)
if err != nil && strings.Contains(err.Error(), "not waiting for human input") {
    // another worker already answered; treat as success/no-op
}

Prevention

When it happens

Trigger: Calling ResumeInput on a run that is still running, already done, failed, or paused for approval rather than for input; double-calling ResumeInput after the first call flipped the run to "running".

Common situations: Race conditions where two workers answer the same input prompt concurrently; generic resume handlers that always call ResumeInput; retrying ResumeInput after a transient error when the run already advanced.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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