{"record":{"id":"0b5adce06ca473a3","repo":"charmbracelet/crush","slug":"session-id-is-required-for-creating-a-new-file-0b5adc","errorCode":null,"errorMessage":"session ID is required for creating a new file","messagePattern":"session ID is required for creating a new file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/fetch.go","lineNumber":77,"sourceCode":"\t\tFetchToolName,\n\t\tfetchDescription(),\n\t\tfunc(ctx context.Context, params FetchParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {\n\t\t\tif params.URL == \"\" {\n\t\t\t\treturn fantasy.NewTextErrorResponse(\"URL parameter is required\"), nil\n\t\t\t}\n\n\t\t\tformat := strings.ToLower(params.Format)\n\t\t\tif format != \"text\" && format != \"markdown\" && format != \"html\" {\n\t\t\t\treturn fantasy.NewTextErrorResponse(\"Format must be one of: text, markdown, html\"), nil\n\t\t\t}\n\n\t\t\tif !strings.HasPrefix(params.URL, \"http://\") && !strings.HasPrefix(params.URL, \"https://\") {\n\t\t\t\treturn fantasy.NewTextErrorResponse(\"URL must start with http:// or https://\"), nil\n\t\t\t}\n\n\t\t\tsessionID := GetSessionFromContext(ctx)\n\t\t\tif sessionID == \"\" {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"session ID is required for creating a new file\")\n\t\t\t}\n\n\t\t\tp, err := permissions.Request(\n\t\t\t\tctx,\n\t\t\t\tpermission.CreatePermissionRequest{\n\t\t\t\t\tSessionID:   sessionID,\n\t\t\t\t\tPath:        workingDir,\n\t\t\t\t\tToolCallID:  call.ID,\n\t\t\t\t\tToolName:    FetchToolName,\n\t\t\t\t\tAction:      \"fetch\",\n\t\t\t\t\tDescription: fmt.Sprintf(\"Fetch content from URL: %s\", params.URL),\n\t\t\t\t\tParams:      FetchPermissionsParams(params),\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.ToolResponse{}, err\n\t\t\t}\n\t\t\tif !p {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/fetch.go#L59-L95","documentation":"The fetch tool requires a session ID from the tool context before it can request permission to access the URL. If the context has no session ID, this error (with a copy-pasted 'creating a new file' message from the edit tool) is returned. The message text is misleading; the real issue is a missing session in the context.","triggerScenarios":"Calling the fetch tool with a context that lacks the session ID — direct/programmatic invocations, tests, or custom runners that bypass the agent's session middleware. URL format is validated first, so this fires only after the URL passes the http/https check.","commonSituations":"Integration tests calling the fetch tool directly, plugin/scripted usage that builds its own context, refactors dropping session injection.","solutions":["Attach the session ID to the context via the session-context helper before calling the tool.","Use the agent runtime's context rather than a bare context.Background().","In tests, replicate the coordinator's context setup (session middleware).","Ignore the misleading wording: treat it exactly like the edit tool's missing-session error."],"exampleFix":"// before\nctx := context.Background()\nresp, _ := fetchTool.Run(ctx, params)\n// after\nctx := tools.WithSessionContext(context.Background(), \"sess_123\")\nresp, _ := fetchTool.Run(ctx, params)","handlingStrategy":"validation","validationCode":"func requireFetchSession(ctx context.Context) error {\n\tif tools.GetSessionFromContext(ctx) == \"\" {\n\t\treturn errors.New(\"fetch tool requires a session-scoped context\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"session ID is required\") {\n\t// attach session via WithSessionContext and retry; note the message wording is a known copy-paste artifact\n}","preventionTips":["Route all tool invocations through the agent runtime's session context.","In tests, construct contexts the same way production code does.","Treat this error identically to the edit tool's missing-session error.","Keep session middleware wiring covered by a unit test."],"tags":["session","context","fetch-tool","misleading-message"],"backgroundTag":"missing-session-context","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}