{"record":{"id":"489b431147fd64b0","repo":"charmbracelet/crush","slug":"failed-to-get-last-assistant-message-w","errorCode":null,"errorMessage":"failed to get last assistant message: %w","messagePattern":"failed to get last assistant message: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/app/app.go","lineNumber":459,"sourceCode":"\tif app.AgentCoordinator == nil {\n\t\treturn fmt.Errorf(\"agent configuration is missing\")\n\t}\n\treturn app.AgentCoordinator.UpdateModels(ctx)\n}\n\n// restoreModelFromSession reads the last assistant message in the\n// session and, if it used a different provider/model than the current\n// config, overrides the preferred model in-memory (non-persistent)\n// provided the provider/model is still available. This ensures that\n// continuing a session uses the same model that produced the last\n// response.\nfunc (app *App) restoreModelFromSession(ctx context.Context, sessionID string) error {\n\tlastMsg, err := app.Messages.GetLastAssistantMessage(ctx, sessionID)\n\tif err != nil {\n\t\tif errors.Is(err, sql.ErrNoRows) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"failed to get last assistant message: %w\", err)\n\t}\n\tif lastMsg.Provider == \"\" || lastMsg.Model == \"\" {\n\t\treturn nil\n\t}\n\n\tcfg := app.config.Config()\n\tcurrentLarge := cfg.Models[config.SelectedModelTypeLarge]\n\tif currentLarge.Provider == lastMsg.Provider && currentLarge.Model == lastMsg.Model {\n\t\treturn nil\n\t}\n\n\tif !cfg.IsModelAvailable(lastMsg.Provider, lastMsg.Model) {\n\t\tslog.Debug(\"Skipping model restoration: provider/model not available\",\n\t\t\t\"provider\", lastMsg.Provider,\n\t\t\t\"model\", lastMsg.Model)\n\t\treturn nil\n\t}\n","sourceCodeStart":441,"sourceCodeEnd":477,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/app/app.go#L441-L477","documentation":"restoreModelFromSession reads the last assistant message via app.Messages.GetLastAssistantMessage to restore provider/model on --continue/--last runs. sql.ErrNoRows is treated as success (nothing to restore), but any other DB error is wrapped with this message. It indicates a storage failure while fetching session history.","triggerScenarios":"GetLastAssistantMessage returns a non-ErrNoRows error: SQLite file unreadable/corrupt, table missing (failed migration), or context cancelled during the query.","commonSituations":"Corrupted cache DB; running with a read-only data directory; schema mismatch after downgrading crush; disk-full during query.","solutions":["Check the SQLite DB file is readable and the disk has space","Move the corrupt DB aside so a fresh one is created","Run crush once with SLOG_LEVEL=debug to identify the migration/query failure","Reinstall/upgrade crush if migrations are out of sync with the DB version"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if _, err := os.Stat(dbPath); err != nil {\n\treturn fmt.Errorf(\"session DB missing/corrupt: %s\", dbPath)\n}\n// only continue sessions that actually have history\nif !sessionHasAssistantMessages(sessionID) {\n\t// proceed without restore — crush treats ErrNoRows as no-op\n}","typeGuard":null,"tryCatchPattern":"if err := app.RunNonInteractive(ctx, w, prompt, \"\", \"\", true, contID, useLast); err != nil {\n\tif strings.Contains(err.Error(), \"failed to get last assistant message\") {\n\t\treturn fmt.Errorf(\"session history unreadable; start a new session: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Ensure the crush data directory is readable and has free space","Don't downgrade across schema migrations; back up the DB first","If the DB is corrupt, move it aside so a fresh one is created"],"tags":["go","sqlite","session-restore","persistence"],"backgroundTag":"database-query-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}