fix(error): replace misleading Database error suggestions
The Database(rusqlite::Error) catch-all variant was suggesting 'lore reset --yes' for ALL database errors, including transient SQLITE_BUSY lock contention. This was wrong on two counts: 1. `lore reset` is not implemented (prints "not yet implemented") 2. Nuking the database is not the fix for a transient lock Changes: - Detect SQLITE_BUSY specifically via sqlite_error_code() and provide targeted advice: "Another process has the database locked" with common causes (cron sync, concurrent lore command) - Map SQLITE_BUSY to ErrorCode::DatabaseLocked (exit code 9) instead of DatabaseError (exit code 10) — semantically correct - Set BUSY actions to ["lore cron status"] (diagnostic) instead of the useless "lore sync --force" (--force overrides the app-level lock table, but SQLITE_BUSY fires before that table is even reached) - Fix MigrationFailed suggestion: also referenced non-existent 'lore reset', now says "try again" with lore migrate / lore doctor - Non-BUSY database errors get a simpler suggestion pointing to lore doctor (no more phantom reset command) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -180,7 +180,13 @@ impl LoreError {
|
|||||||
Self::DatabaseLocked { .. } => ErrorCode::DatabaseLocked,
|
Self::DatabaseLocked { .. } => ErrorCode::DatabaseLocked,
|
||||||
Self::MigrationFailed { .. } => ErrorCode::MigrationFailed,
|
Self::MigrationFailed { .. } => ErrorCode::MigrationFailed,
|
||||||
Self::TokenNotSet { .. } => ErrorCode::TokenNotSet,
|
Self::TokenNotSet { .. } => ErrorCode::TokenNotSet,
|
||||||
Self::Database(_) => ErrorCode::DatabaseError,
|
Self::Database(e) => {
|
||||||
|
if e.sqlite_error_code() == Some(rusqlite::ErrorCode::DatabaseBusy) {
|
||||||
|
ErrorCode::DatabaseLocked
|
||||||
|
} else {
|
||||||
|
ErrorCode::DatabaseError
|
||||||
|
}
|
||||||
|
}
|
||||||
Self::Http(_) => ErrorCode::GitLabNetworkError,
|
Self::Http(_) => ErrorCode::GitLabNetworkError,
|
||||||
Self::Json(_) => ErrorCode::InternalError,
|
Self::Json(_) => ErrorCode::InternalError,
|
||||||
Self::Io(_) => ErrorCode::IoError,
|
Self::Io(_) => ErrorCode::IoError,
|
||||||
@@ -218,14 +224,20 @@ impl LoreError {
|
|||||||
"Wait for other sync to complete or use --force.\n\n Example:\n lore ingest --force\n lore ingest issues --force",
|
"Wait for other sync to complete or use --force.\n\n Example:\n lore ingest --force\n lore ingest issues --force",
|
||||||
),
|
),
|
||||||
Self::MigrationFailed { .. } => Some(
|
Self::MigrationFailed { .. } => Some(
|
||||||
"Check database file permissions or reset with 'lore reset'.\n\n Example:\n lore migrate\n lore reset --yes",
|
"Check database file permissions and try again.\n\n Example:\n lore migrate\n lore doctor",
|
||||||
),
|
),
|
||||||
Self::TokenNotSet { .. } => Some(
|
Self::TokenNotSet { .. } => Some(
|
||||||
"Set your token:\n\n lore token set\n\n Or export to your shell:\n\n export GITLAB_TOKEN=glpat-xxxxxxxxxxxx\n\n Your token needs the read_api scope.",
|
"Set your token:\n\n lore token set\n\n Or export to your shell:\n\n export GITLAB_TOKEN=glpat-xxxxxxxxxxxx\n\n Your token needs the read_api scope.",
|
||||||
),
|
),
|
||||||
Self::Database(_) => Some(
|
Self::Database(e) => {
|
||||||
"Check database file permissions or reset with 'lore reset'.\n\n Example:\n lore doctor\n lore reset --yes",
|
if e.sqlite_error_code() == Some(rusqlite::ErrorCode::DatabaseBusy) {
|
||||||
),
|
Some(
|
||||||
|
"Another process has the database locked. Wait a moment and retry.\n\n Common causes:\n - A cron sync is running (lore cron status)\n - Another lore command is active",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Some("Check database file permissions.\n\n Example:\n lore doctor")
|
||||||
|
}
|
||||||
|
}
|
||||||
Self::Http(_) => Some("Check network connection"),
|
Self::Http(_) => Some("Check network connection"),
|
||||||
Self::NotFound(_) => {
|
Self::NotFound(_) => {
|
||||||
Some("Verify the entity exists.\n\n Example:\n lore issues\n lore mrs")
|
Some("Verify the entity exists.\n\n Example:\n lore issues\n lore mrs")
|
||||||
@@ -267,6 +279,11 @@ impl LoreError {
|
|||||||
Self::OllamaUnavailable { .. } => vec!["ollama serve"],
|
Self::OllamaUnavailable { .. } => vec!["ollama serve"],
|
||||||
Self::OllamaModelNotFound { .. } => vec!["ollama pull nomic-embed-text"],
|
Self::OllamaModelNotFound { .. } => vec!["ollama pull nomic-embed-text"],
|
||||||
Self::DatabaseLocked { .. } => vec!["lore ingest --force"],
|
Self::DatabaseLocked { .. } => vec!["lore ingest --force"],
|
||||||
|
Self::Database(e)
|
||||||
|
if e.sqlite_error_code() == Some(rusqlite::ErrorCode::DatabaseBusy) =>
|
||||||
|
{
|
||||||
|
vec!["lore cron status"]
|
||||||
|
}
|
||||||
Self::EmbeddingsNotBuilt => vec!["lore embed"],
|
Self::EmbeddingsNotBuilt => vec!["lore embed"],
|
||||||
Self::EmbeddingFailed { .. } => vec!["lore embed --retry-failed"],
|
Self::EmbeddingFailed { .. } => vec!["lore embed --retry-failed"],
|
||||||
Self::MigrationFailed { .. } => vec!["lore migrate"],
|
Self::MigrationFailed { .. } => vec!["lore migrate"],
|
||||||
|
|||||||
Reference in New Issue
Block a user