micro/go-micro · error

agent: checkpointed run is terminal with status

Error message

agent: checkpointed run is terminal with status 

What it means

The checkpointed run is in a terminal state (per terminalAgentRunStatus), so it cannot be resumed. Terminal runs have finished (successfully, failed, or otherwise permanently stopped) and no further work can be streamed.

Source

Thrown at agent/stream.go:159

	if a.opts.Checkpoint == nil {
		return nil, errors.New("agent: ResumeStreamAsk requires a checkpoint")
	}
	run, ok, err := a.opts.Checkpoint.Load(ctx, runID)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, errors.New("agent: checkpointed run not found")
	}
	if run.Status == "done" {
		var resp Response
		if err := json.Unmarshal(run.State.Data, &resp); err != nil {
			return nil, err
		}
		return &resp, nil
	}
	if terminalAgentRunStatus(run.Status) {
		return nil, errors.New("agent: checkpointed run is terminal with status " + run.Status)
	}

	a.mu.Lock()
	defer a.mu.Unlock()
	if a.tools == nil {
		a.tools = ai.NewTools(a.opts.Registry, ai.ToolClient(a.opts.Client))
	}
	base := a.toolHandler()
	handler := func(ctx context.Context, call ai.ToolCall) ai.ToolResult {
		_ = sendStreamEvent(ctx, events, &StreamEvent{Type: StreamEventToolStart, ToolCall: call})
		result := base(ctx, call)
		_ = sendStreamEvent(ctx, events, &StreamEvent{Type: StreamEventToolEnd, ToolCall: call, Result: result})
		return result
	}
	a.setupWithToolHandler(handler)
	defer a.setupWithToolHandler(nil)
	if run.Status == "paused" {
		if run.State.Stage == agentInputStep {

View on GitHub (pinned to 24529f1404)

Solutions

  1. Inspect run.Status via Checkpoint.Load before resuming and only resume non-terminal runs
  2. Treat terminal failed runs as unrecoverable: start a new run instead
  3. If the run completed, load and return the persisted Response rather than resuming

Example fix

// before
stream, err := agent.ResumeStreamAsk(ctx, ag, runID)
// after
run, ok, _ := store.Load(ctx, runID)
if ok && run.Status == "failed" {
    return startNewRun(ctx, ag) // don't resume a terminal run
}
stream, err := agent.ResumeStreamAsk(ctx, ag, runID)
Defensive patterns

Strategy: validation

Validate before calling

run, ok, _ := store.Load(ctx, runID)
if ok && run.Status != "running" && run.Status != "paused" {
    return fmt.Errorf("run %s is terminal (%s); cannot resume", runID, run.Status)
}

Try / catch

stream, err := agent.ResumeStreamAsk(ctx, ag, runID)
if err != nil && strings.Contains(err.Error(), "terminal with status") {
    return fmt.Errorf("run already finished; fetch result or start a new run")
}

Prevention

When it happens

Trigger: Calling ResumeStreamAsk/ResumeStream on a run whose stored Status is a terminal value other than "done" (e.g. failed/canceled status), after that status was persisted by a prior run.

Common situations: Retrying a resume after the run already failed; double-resuming a canceled run; race where another process terminated the run between status check and resume.

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/1dd456bb47ca3b92. Report an issue: GitHub.