{"record":{"id":"c4fa412a2d2540b9","repo":"charmbracelet/crush","slug":"agent-message-id-missing-from-context-c4fa41","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/agentic_fetch_tool.go","lineNumber":41,"sourceCode":"type agenticFetchValidationResult struct {\n\tSessionID      string\n\tAgentMessageID string\n}\n\n// validateAgenticFetchParams validates the tool call parameters and extracts required context values.\nfunc validateAgenticFetchParams(ctx context.Context, params tools.AgenticFetchParams) (agenticFetchValidationResult, error) {\n\tif params.Prompt == \"\" {\n\t\treturn agenticFetchValidationResult{}, errors.New(\"prompt is required\")\n\t}\n\n\tsessionID := tools.GetSessionFromContext(ctx)\n\tif sessionID == \"\" {\n\t\treturn agenticFetchValidationResult{}, errors.New(\"session id missing from context\")\n\t}\n\n\tagentMessageID := tools.GetMessageFromContext(ctx)\n\tif agentMessageID == \"\" {\n\t\treturn agenticFetchValidationResult{}, errors.New(\"agent message id missing from context\")\n\t}\n\n\treturn agenticFetchValidationResult{\n\t\tSessionID:      sessionID,\n\t\tAgentMessageID: agentMessageID,\n\t}, nil\n}\n\n//go:embed templates/agentic_fetch_prompt.md.tpl\nvar agenticFetchPromptTmpl []byte\n\nfunc (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) (fantasy.AgentTool, error) {\n\tif client == nil {\n\t\ttransport := http.DefaultTransport.(*http.Transport).Clone()\n\t\ttransport.MaxIdleConns = 100\n\t\ttransport.MaxIdleConnsPerHost = 10\n\t\ttransport.IdleConnTimeout = 90 * time.Second\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/agentic_fetch_tool.go#L23-L59","documentation":"validateAgenticFetchParams finally reads the parent agent message id via tools.GetMessageFromContext(ctx). The fetch sub-run attaches its results to that parent message; a missing id would orphan the tool result, so the validator returns this error after the session check passes.","triggerScenarios":"Calling the agentic fetch handler with a context that has the session id set but not the message id — usually a hand-rolled dispatcher that only set the session value.","commonSituations":"Custom tool execution loops; partially migrated test harnesses that set session but not message context; invoking the tool outside the coordinator.","solutions":["Set the message context value (tools.WithMessageContext) in addition to the session value.","Prefer routing the call through the coordinator, which sets both ids automatically.","Pair the two context decorators together in test helpers to prevent recurrence."],"exampleFix":"// before\nctx = tools.WithSessionContext(ctx, sessionID)\n// handler fails on message id\n// after\nctx = tools.WithSessionContext(ctx, sessionID)\nctx = tools.WithMessageContext(ctx, agentMessageID)","handlingStrategy":"validation","validationCode":"if tools.GetMessageFromContext(ctx) == \"\" {\n    return errors.New(\"agentic fetch requires agent message context\")\n}","typeGuard":null,"tryCatchPattern":"res, err := validateAgenticFetchParams(ctx, params)\nif err != nil && strings.Contains(err.Error(), \"agent message id missing from context\") {\n    ctx = tools.WithMessageContext(ctx, agentMessageID)\n    res, err = validateAgenticFetchParams(ctx, params)\n}","preventionTips":["Pair session and message context decorators in one helper function.","Check both ids in dispatch middleware before any tool runs.","Cover the context setup path in integration tests."],"tags":["context","message-id","validation","agentic-fetch"],"backgroundTag":"missing-context-value","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}