{"record":{"id":"6caa1d83b5725fd4","repo":"gitbutlerapp/gitbutler","slug":"diffing-thread-crashed","errorCode":null,"errorMessage":"diffing-thread crashed","messagePattern":"diffing-thread crashed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/gitbutler-branch-actions/src/branch.rs","lineNumber":843,"sourceCode":"                    }\n                    Ok(())\n                }\n            })?;\n\n        for branch in branches {\n            let Some((base, authors, num_commits)) = merge_rx.recv()? else {\n                continue;\n            };\n\n            let branch_head = branch.head;\n            let base_commit = repo.find_object(base)?.try_into_commit()?;\n            let base_tree = base_commit.tree()?;\n            let head_tree = repo.find_object(branch_head)?.peel_to_tree()?;\n\n            let ((change_tx, change_rx), (res_tx, rex_rx)) =\n                (std::sync::mpsc::channel(), std::sync::mpsc::channel());\n            if start.send((change_rx, res_tx)).is_err() {\n                bail!(\"diffing-thread crashed\");\n            };\n            base_tree\n                .changes()?\n                .options(|opts| {\n                    opts.track_rewrites(None);\n                })\n                // NOTE: `stats(head_tree)` is also possible, but we have a separate thread for that.\n                .for_each_to_obtain_tree(&head_tree, move |change| -> anyhow::Result<Action> {\n                    change_tx.send(change.detach()).ok();\n                    Ok(std::ops::ControlFlow::Continue(()))\n                })?;\n            let (number_of_files, lines_added, lines_removed) = rex_rx.recv()?;\n\n            let branch_data = BranchListingDetails {\n                name: branch.name,\n                lines_added,\n                lines_removed,\n                number_of_files,","sourceCodeStart":825,"sourceCodeEnd":861,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/gitbutler-branch-actions/src/branch.rs#L825-L861","documentation":"Branch listing details offload per-file line counting to a dedicated `gitbutler-diff-stats` thread fed over mpsc channels. The bail fires when `start.send(...)` fails, which can only happen once the receiving channel end in that thread was dropped — i.e. the diff-stats thread already exited, either because its initialization (`for_tree_diffing` / `diff_resource_cache_for_tree_diff`) failed or it panicked. The error therefore points at an earlier crash in the background worker, not at the send itself.","triggerScenarios":"Calling the branch listing API while the `gitbutler-diff-stats` thread dies at startup (repository state its gix calls reject) or panics while handling a previous branch's diff, so subsequent `start.send` for the next branch fails.","commonSituations":"Corrupted packfiles or object database; repository mutated concurrently (git gc/prune, another Git client) while stats were computed; a GitButler bug panicking inside the diff-stats loop.","solutions":["Check application logs for a panic or error from the `gitbutler-diff-stats` thread — that is the real failure","Run `git fsck` in the affected repository to rule out object database corruption","Restart the app and retry; a transient init failure usually clears","If it reproduces deterministically, capture the backtrace and report it as a GitButler bug"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match list_branch_listing_details(ctx) {\n    Ok(details) => { /* continue */ }\n    Err(err) if err.to_string().contains(\"diffing-thread crashed\") => {\n        // the gitbutler-diff-stats worker died; check its panic log, restart, retry once\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Treat this error as a symptom: always pull the panic log from the gitbutler-diff-stats thread","Run `git fsck` on repositories that hit it repeatedly to rule out object corruption","Avoid running `git gc --prune` concurrently with GitButler operations"],"tags":["rust","gitbutler","thread-crash","diff-stats","concurrency"],"backgroundTag":"worker-thread-panic","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}