{"record":{"id":"037a81ee0ffee0b5","repo":"charmbracelet/crush","slug":"agent-message-id-missing-from-context","errorCode":null,"errorMessage":"agent message id missing from context","messagePattern":"agent message id missing from context","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/agent_tool.go","lineNumber":55,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn fantasy.NewParallelAgentTool(\n\t\tAgentToolName,\n\t\tagentToolDescription,\n\t\tfunc(ctx context.Context, params AgentParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {\n\t\t\tif params.Prompt == \"\" {\n\t\t\t\treturn fantasy.NewTextErrorResponse(\"prompt is required\"), nil\n\t\t\t}\n\n\t\t\tsessionID := tools.GetSessionFromContext(ctx)\n\t\t\tif sessionID == \"\" {\n\t\t\t\treturn fantasy.ToolResponse{}, errors.New(\"session id missing from context\")\n\t\t\t}\n\n\t\t\tagentMessageID := tools.GetMessageFromContext(ctx)\n\t\t\tif agentMessageID == \"\" {\n\t\t\t\treturn fantasy.ToolResponse{}, errors.New(\"agent message id missing from context\")\n\t\t\t}\n\n\t\t\treturn c.runSubAgent(ctx, subAgentParams{\n\t\t\t\tAgent:          agent,\n\t\t\t\tSessionID:      sessionID,\n\t\t\t\tAgentMessageID: agentMessageID,\n\t\t\t\tToolCallID:     call.ID,\n\t\t\t\tPrompt:         params.Prompt,\n\t\t\t\tSessionTitle:   \"New Agent Session\",\n\t\t\t})\n\t\t},\n\t), nil\n}\n","sourceCodeStart":37,"sourceCodeEnd":69,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/agent_tool.go#L37-L69","documentation":"The 'agent' tool handler also requires the parent assistant message id from context via tools.GetMessageFromContext(ctx). The sub-agent's output is recorded as part of that parent message (tool result linkage); without it, message bookkeeping would break, so the tool returns this error.","triggerScenarios":"Same as error 2 but for the message id: executing the agent tool with a context lacking the message value set by the agent loop (empty GetMessageFromContext result).","commonSituations":"Direct tool invocation in tests or scripts; custom execution paths that set the session but forget the message context; re-implementations of the tool dispatch loop.","solutions":["Run the tool through the normal coordinator dispatch, which attaches the agent message id.","In custom callers, set the message context (tools.WithMessageContext / equivalent) alongside the session id.","Ensure both session and message ids are set together — the checks are sequential and both are required."],"exampleFix":"// before\nctx = tools.WithSessionContext(ctx, sessionID)\n// after\nctx = tools.WithSessionContext(ctx, sessionID)\nctx = tools.WithMessageContext(ctx, agentMessageID)","handlingStrategy":"validation","validationCode":"if tools.GetSessionFromContext(ctx) == \"\" || tools.GetMessageFromContext(ctx) == \"\" {\n    return errors.New(\"session and message context values required before executing agent tool\")\n}","typeGuard":null,"tryCatchPattern":"resp, err := tool.Execute(ctx, params)\nif err != nil && strings.Contains(err.Error(), \"agent message id missing from context\") {\n    ctx = tools.WithMessageContext(ctx, agentMessageID)\n    resp, err = tool.Execute(ctx, params)\n}","preventionTips":["Set session and message context values together in one helper so neither is forgotten.","Route all sub-agent tool invocations through the coordinator loop.","Assert both context values exist in tool-dispatch middleware."],"tags":["context","message-id","tool-execution"],"backgroundTag":"missing-context-value","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}