{"record":{"id":"390d03e7a37327ff","repo":"micro/go-micro","slug":"agent-run-s-has-unfinished-plan-steps-s","errorCode":null,"errorMessage":"agent run %s has unfinished plan steps: %s","messagePattern":"agent run (.+?) has unfinished plan steps: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/agent.go","lineNumber":552,"sourceCode":"\t\t\treply += \"\\n\\n\"\n\t\t}\n\t\treply += resp.Answer\n\t}\n\n\tcompletedToolCalls := checkpointToolCalls(run.Steps)\n\tif a.currentRun != nil {\n\t\tcompletedToolCalls = checkpointToolCalls(a.currentRun.Steps)\n\t}\n\tres := &Response{\n\t\tReply:     reply,\n\t\tToolCalls: mergeCheckpointToolCalls(completedToolCalls, resp.ToolCalls),\n\t\tAgent:     a.opts.Name,\n\t\tRunID:     a.runID,\n\t\tParentID:  parentRunID,\n\t}\n\tif a.opts.Checkpoint != nil {\n\t\tif unfinished := a.unfinishedPlanSteps(); len(unfinished) > 0 {\n\t\t\terr = fmt.Errorf(\"agent run %s has unfinished plan steps: %s\", run.ID, strings.Join(unfinished, \", \"))\n\t\t\trun.Status = \"failed\"\n\t\t\trun.State.Stage = agentAskStep\n\t\t\trun.State.Data = []byte(message)\n\t\t\tif a.currentRun != nil {\n\t\t\t\trun.Steps = a.currentRun.Steps\n\t\t\t}\n\t\t\tif len(run.Steps) == 0 {\n\t\t\t\trun.Steps = []flow.StepRecord{{Name: agentAskStep}}\n\t\t\t}\n\t\t\trun.Steps[0].Status = \"failed\"\n\t\t\trun.Steps[0].Error = err.Error()\n\t\t\t_ = a.saveRun(ctx, run)\n\t\t\treturn nil, err\n\t\t}\n\t}\n\trun.Status = \"done\"\n\trun.State.Stage = \"\"\n\tif b, marshalErr := json.Marshal(res); marshalErr == nil {","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/agent/agent.go#L534-L570","documentation":"Before continuing a checkpointed run, the agent checks for unfinished plan steps (agent/agent.go:552). If any remain, it marks the run failed, saves state so a later resume restarts from the saved input message, and returns this error listing the unfinished step names. It prevents skipping half-completed plan work.","triggerScenarios":"Calling Ask/Chat on an agent with Checkpoint configured while a previous run's plan has steps not yet completed (unfinishedPlanSteps() non-empty); also surfaced in streaming tests like TestA2AStreamUsesAgentChatPathWithTools.","commonSituations":"Reusing an agent mid-plan without resuming properly, a crashed prior run leaving plan steps open, concurrent Ask calls on the same checkpointed agent, or resetting memory/checkpoint without clearing plan state.","solutions":["Call agent.Resume(ctx, ag, runID) to continue the interrupted plan instead of starting a new Ask","Complete or cancel the outstanding plan steps, then retry the request","Use a fresh agent/run (or clear the checkpoint) if the old plan should be abandoned","Serialize access to the agent — avoid concurrent Ask calls on the same checkpointed agent","Inspect the listed step names in the error to see exactly which work is pending"],"exampleFix":"// before\nresp, err := ag.Ask(ctx, newMsg) // unfinished plan steps error\n// after\nresp, err := agent.Resume(ctx, ag, lastRunID) // continue existing plan\nif err != nil {\n    resp, err = ag.Ask(ctx, newMsg) // only after plan resolved\n}\n","handlingStrategy":"validation","validationCode":"// before Ask, ensure no unfinished plan steps on the last checkpointed run\nruns, err := agent.Pending(ctx, ag)\nif err == nil && len(runs) > 0 {\n    // resume those runs first instead of calling Ask\n}","typeGuard":null,"tryCatchPattern":"resp, err := ag.Ask(ctx, msg)\nif err != nil && strings.Contains(err.Error(), \"unfinished plan steps\") {\n    // finish or cancel the plan, or resume the run, then retry\n    return recoverPlan(err)\n}","preventionTips":["Resume interrupted runs before issuing new Ask calls","Serialize Ask calls per checkpointed agent","After crashes, drain pending runs at startup with ResumePending","Clear/cancel abandoned plans explicitly before starting fresh work"],"tags":["go","agent","plan-steps","checkpoint","state-conflict"],"backgroundTag":"unfinished-plan-steps","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}