{"record":{"id":"99bb7c7ce1b279fb","repo":"charmbracelet/crush","slug":"failed-to-get-session-w-99bb7c","errorCode":null,"errorMessage":"failed to get session: %w","messagePattern":"failed to get session: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/todos.go","lineNumber":48,"sourceCode":"\tJustCompleted []string       `json:\"just_completed,omitempty\"`\n\tJustStarted   string         `json:\"just_started,omitempty\"`\n\tCompleted     int            `json:\"completed\"`\n\tTotal         int            `json:\"total\"`\n}\n\nfunc NewTodosTool(sessions session.Service) fantasy.AgentTool {\n\treturn fantasy.NewAgentTool(\n\t\tTodosToolName,\n\t\ttodosDescription,\n\t\tfunc(ctx context.Context, params TodosParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {\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 managing todos\")\n\t\t\t}\n\n\t\t\tcurrentSession, err := sessions.Get(ctx, sessionID)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"failed to get session: %w\", err)\n\t\t\t}\n\n\t\t\tisNew := len(currentSession.Todos) == 0\n\t\t\toldStatusByContent := make(map[string]session.TodoStatus)\n\t\t\tfor _, todo := range currentSession.Todos {\n\t\t\t\toldStatusByContent[todo.Content] = todo.Status\n\t\t\t}\n\n\t\t\tfor _, item := range params.Todos {\n\t\t\t\tswitch item.Status {\n\t\t\t\tcase \"pending\", \"in_progress\", \"completed\":\n\t\t\t\tdefault:\n\t\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"invalid status %q for todo %q\", item.Status, item.Content)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttodos := make([]session.Todo, len(params.Todos))\n\t\t\tvar justCompleted []string","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/todos.go#L30-L66","documentation":"The session ID was present in the context but sessions.Get(ctx, sessionID) failed to load the session from the session service (SQLite-backed). The underlying error (e.g. record not found, DB failure) is wrapped with %w so the root cause is preserved for errors.Is/As.","triggerScenarios":"Calling the todos tool with a session ID that does not exist in the database (deleted or stale session), the session service not being initialized/connected, or the SQLite DB being corrupted or locked.","commonSituations":"Resuming a session that was deleted; passing a fabricated session ID in tests; DB migration mismatch or read-only database file; concurrent access locking the SQLite store.","solutions":["Verify the session ID exists before invoking the tool (sessions.Get or session list)","Check the DB file exists, is writable, and migrations ran (the wrapped error tells you if it's not-found vs I/O)","Create a fresh session if the old one was deleted","If DB-locked, close other connections or enable busy timeout"],"exampleFix":"// before\nsessions.Get(ctx, \"abc123\") // stale/deleted ID\n// after\nif _, err := sessions.Get(ctx, sessionID); err != nil {\n    sessionID, err = createOrResolveSession(ctx)\n}","handlingStrategy":"validation","validationCode":"if _, err := sessions.Get(ctx, sessionID); err != nil {\n    return fmt.Errorf(\"session %s does not exist: %w\", sessionID, err)\n}","typeGuard":"func sessionExists(ctx context.Context, svc session.Service, id string) bool {\n    _, err := svc.Get(ctx, id)\n    return err == nil\n}","tryCatchPattern":"var nf *session.NotFoundError\nif errors.As(err, &nf) {\n    // recreate or re-resolve the session, then retry\n} else if errors.Is(err, sqlite.ErrLocked) {\n    // wait/retry with backoff\n}","preventionTips":["Check the wrapped errors.Is/As cause to distinguish not-found from DB failure","Don't hardcode or fabricate session IDs; obtain them from the session service","Keep the DB file writable and migrations current"],"tags":["go","database","sqlite","session"],"backgroundTag":"record-not-found","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}