{"record":{"id":"ee077badbf9cf1f8","repo":"charmbracelet/crush","slug":"s","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/edit.go","lineNumber":287,"sourceCode":"\treturn nil\n}\n\nfunc loadExistingFile(edit editContext, filePath, sessionError string) (sessionID, oldContent string, isCrlf bool, resp fantasy.ToolResponse, err error) {\n\tfileInfo, err := os.Stat(filePath)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn \"\", \"\", false, fantasy.NewTextErrorResponse(fmt.Sprintf(\"file not found: %s\", filePath)), nil\n\t\t}\n\t\treturn \"\", \"\", false, fantasy.ToolResponse{}, fmt.Errorf(\"failed to access file: %w\", err)\n\t}\n\n\tif fileInfo.IsDir() {\n\t\treturn \"\", \"\", false, fantasy.NewTextErrorResponse(fmt.Sprintf(\"path is a directory, not a file: %s\", filePath)), nil\n\t}\n\n\tsessionID = GetSessionFromContext(edit.ctx)\n\tif sessionID == \"\" {\n\t\treturn \"\", \"\", false, fantasy.ToolResponse{}, fmt.Errorf(\"%s\", sessionError)\n\t}\n\n\tlastRead := edit.filetracker.LastReadTime(edit.ctx, sessionID, filePath)\n\tif lastRead.IsZero() {\n\t\treturn \"\", \"\", false, fantasy.NewTextErrorResponse(\"you must read the file before editing it. Use the View tool first\"), nil\n\t}\n\n\tmodTime := fileInfo.ModTime().Truncate(time.Second)\n\tif modTime.After(lastRead) {\n\t\treturn \"\", \"\", false, fantasy.NewTextErrorResponse(\n\t\t\tfmt.Sprintf(\n\t\t\t\t\"file %s has been modified since it was last read (mod time: %s, last read: %s)\",\n\t\t\t\tfilePath, modTime.Format(time.RFC3339), lastRead.Format(time.RFC3339),\n\t\t\t),\n\t\t), nil\n\t}\n\n\tcontent, err := os.ReadFile(filePath)","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/edit.go#L269-L305","documentation":"The edit tool requires an active session ID stored in the tool context (GetSessionFromContext). When the context carries no session ID, the requested sessionError string is surfaced via this format call. Without a session, the tool cannot associate file history or the file tracker with a conversation.","triggerScenarios":"Invoking the edit tool programmatically (or via a custom runner) with a context that never had the session ID attached — e.g. building editContext with context.Background() instead of the session-scoped context, or calling the tool outside the agent's normal execution flow.","commonSituations":"Tests and integrations that call tools directly, custom scripts driving the tool API, refactors that drop the context-with-session middleware.","solutions":["Attach the session ID to the context using the tool package's WithSession helper before invoking the edit tool.","Use the session-scoped context passed by the agent runtime rather than context.Background().","In tests, construct the context the same way the coordinator does (session middleware included).","Check for regressions that replaced the enriched context when wiring editContext."],"exampleFix":"// before\nctx := context.Background()\n// after\nctx := tools.WithSessionContext(ctx, sessionID)","handlingStrategy":"validation","validationCode":"func requireSession(ctx context.Context) (string, error) {\n\tsid := tools.GetSessionFromContext(ctx)\n\tif sid == \"\" {\n\t\treturn \"\", errors.New(\"context has no session ID; use the session-scoped context\")\n\t}\n\treturn sid, nil\n}","typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"session\") && strings.Contains(err.Error(), \"required\") {\n\t// rebuild ctx with the session middleware and re-invoke the tool\n}","preventionTips":["Always derive tool contexts from the agent runtime, never context.Background().","In tests, mirror the coordinator's context setup including session injection.","Add a startup assertion that the session middleware is installed.","Review refactors that touch context construction for dropped values."],"tags":["session","context","edit-tool","go"],"backgroundTag":"missing-session-context","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}