{"record":{"id":"dfd69085de60cad6","repo":"gitbutlerapp/gitbutler","slug":"failed-to-list-actions-e","errorCode":null,"errorMessage":"Failed to list actions: {e}","messagePattern":"Failed to list actions: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-action/src/action.rs","lineNumber":195,"sourceCode":"        snapshot_before,\n        snapshot_after,\n        response,\n        source,\n    );\n    let id = action.id;\n    persist_action(db, action)?;\n    Ok(id)\n}\n\n/// List persisted Butler actions from `db` using `offset` and `limit` pagination.\n///\n/// Invalid database rows are skipped to preserve the historical best-effort behavior of the\n/// action list endpoint.\npub fn list_actions(db: &DbHandle, offset: i64, limit: i64) -> anyhow::Result<ActionListing> {\n    let (total, actions) = db\n        .butler_actions()\n        .list(offset, limit)\n        .map_err(|e| anyhow::anyhow!(\"Failed to list actions: {e}\"))?;\n\n    // Filter out any entries that cannot be converted to ButlerAction\n    let actions = actions\n        .into_iter()\n        .filter_map(|a| TryInto::try_into(a).ok())\n        .collect::<Vec<_>>();\n    Ok(ActionListing { total, actions })\n}\n\n#[derive(Debug, Clone, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct ActionListing {\n    pub total: i64,\n    pub actions: Vec<ButlerAction>,\n}\n","sourceCodeStart":177,"sourceCodeEnd":211,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but-action/src/action.rs#L177-L211","documentation":"anyhow wrapper at crates/but-action/src/action.rs:195 around the paginated SELECT over butler_actions (offset/limit). Rows that fail to convert to ButlerAction are deliberately skipped afterwards (filter_map preserves best-effort listing), so this error means the query itself failed — a locked or unreadable database or a missing table — not malformed rows.","triggerScenarios":"Reading the action history when the butler_actions table does not exist (database created by an older binary without migrations), the database is locked by a concurrent writer, or the file is corrupt or unreadable.","commonSituations":"Opening a legacy project database without running migrations; the desktop app writing while the CLI lists actions; a truncated database file on a failing disk.","solutions":["Read {e}: \"no such table\" means migrations must run; \"database is locked\" means retry after the concurrent writer finishes","Upgrade to a binary whose schema matches the project database","Close concurrent GitButler processes holding the project","If the database is corrupt, rebuild the project database — action history is best-effort data"],"exampleFix":"// before\nlet (total, actions) = db.butler_actions().list(offset, limit)\n\t.map_err(|e| anyhow::anyhow!(\"Failed to list actions: {e}\"))?;\n\n// after — include the pagination window for faster diagnosis\nlet (total, actions) = db.butler_actions().list(offset, limit)\n\t.map_err(|e| anyhow::anyhow!(\"Failed to list actions (offset {offset}, limit {limit}): {e}\"))?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match list_actions(&db, offset, limit) {\n    Ok(listing) => render(listing),\n    Err(e) => {\n        log::warn!(\"action history unavailable: {e:#}\");\n        // do NOT fake an empty history — surface an explicit unavailable state\n        render_unavailable(\"Action history is unavailable.\");\n    }\n}","preventionTips":["Open project databases only with binaries that have run current migrations","Avoid concurrent writers; acquire repository access locks at API boundaries","Distinguish query failure from an empty history in UI states","Read the chained cause: \"no such table\" means migration debt, \"locked\" means concurrency"],"tags":["database","sqlite","rust","pagination"],"backgroundTag":"database-query-failed","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}