charmbracelet/crush · error
%s
Error message
%s
What it means
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.
Source
Thrown at internal/agent/tools/edit.go:287
return nil
}
func loadExistingFile(edit editContext, filePath, sessionError string) (sessionID, oldContent string, isCrlf bool, resp fantasy.ToolResponse, err error) {
fileInfo, err := os.Stat(filePath)
if err != nil {
if os.IsNotExist(err) {
return "", "", false, fantasy.NewTextErrorResponse(fmt.Sprintf("file not found: %s", filePath)), nil
}
return "", "", false, fantasy.ToolResponse{}, fmt.Errorf("failed to access file: %w", err)
}
if fileInfo.IsDir() {
return "", "", false, fantasy.NewTextErrorResponse(fmt.Sprintf("path is a directory, not a file: %s", filePath)), nil
}
sessionID = GetSessionFromContext(edit.ctx)
if sessionID == "" {
return "", "", false, fantasy.ToolResponse{}, fmt.Errorf("%s", sessionError)
}
lastRead := edit.filetracker.LastReadTime(edit.ctx, sessionID, filePath)
if lastRead.IsZero() {
return "", "", false, fantasy.NewTextErrorResponse("you must read the file before editing it. Use the View tool first"), nil
}
modTime := fileInfo.ModTime().Truncate(time.Second)
if modTime.After(lastRead) {
return "", "", false, fantasy.NewTextErrorResponse(
fmt.Sprintf(
"file %s has been modified since it was last read (mod time: %s, last read: %s)",
filePath, modTime.Format(time.RFC3339), lastRead.Format(time.RFC3339),
),
), nil
}
content, err := os.ReadFile(filePath)View on GitHub (pinned to 7944b8e522)
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.
Example fix
// before ctx := context.Background() // after ctx := tools.WithSessionContext(ctx, sessionID)
Defensive patterns
Strategy: validation
Validate before calling
func requireSession(ctx context.Context) (string, error) {
sid := tools.GetSessionFromContext(ctx)
if sid == "" {
return "", errors.New("context has no session ID; use the session-scoped context")
}
return sid, nil
} Try / catch
if strings.Contains(err.Error(), "session") && strings.Contains(err.Error(), "required") {
// rebuild ctx with the session middleware and re-invoke the tool
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Tests and integrations that call tools directly, custom scripts driving the tool API, refactors that drop the context-with-session middleware.
Related errors
- session ID is required for creating a new file
- session ID is required for managing todos
- session ID is required for accessing files outside working d
- session_id is required
- session id missing from context
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/ee077badbf9cf1f8.
Report an issue: GitHub.