{"record":{"id":"87800c2ef8804ebb","repo":"gitbutlerapp/gitbutler","slug":"we-never-return-these-as-the-status-iteration-is-c","errorCode":null,"errorMessage":"we never return these as the status iteration is configured accordingly","messagePattern":"we never return these as the status iteration is configured accordingly","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-core/src/diff/worktree.rs","lineNumber":487,"sourceCode":"\n            status::Item::IndexWorktree(\n                index_worktree::Item::Modification {\n                    status: EntryStatus::NeedsUpdate(_),\n                    ..\n                }\n                | index_worktree::Item::DirectoryContents {\n                    entry:\n                        gix::dir::Entry {\n                            status:\n                                gix::dir::entry::Status::Tracked\n                                | gix::dir::entry::Status::Pruned\n                                | gix::dir::entry::Status::Ignored(_),\n                            ..\n                        },\n                    ..\n                },\n            ) => {\n                unreachable!(\n                    \"we never return these as the status iteration is configured accordingly\"\n                )\n            }\n        };\n        tmp.push(change);\n    }\n\n    tmp.sort_by(|(a_origin, a), (b_origin, b)| {\n        cmp_prefer_overlapping(a, b).then(a_origin.cmp(b_origin).reverse())\n    });\n\n    let mut last_change = None::<&TreeChange>;\n    let mut changes = Vec::<TreeChange>::with_capacity(tmp.len());\n    let (mut filter, index) = repo.filter_pipeline(None)?;\n    let mut path_check = gix::status::plumbing::SymlinkCheck::new(\n        repo.workdir().map(ToOwned::to_owned).context(\"non-bare\")?,\n    );\n    for (_origin, change) in tmp {","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-core/src/diff/worktree.rs#L469-L505","documentation":"While assembling worktree tree changes, but-core's status walker matches `index_worktree::Item::DirectoryContents` entries and marks `Status::Tracked | Status::Pruned | Status::Ignored(_)` as `unreachable!` because the gix status iteration is explicitly configured to never emit those (untracked collection with matching traversal and ignored-entry suppression). Hitting it means the iteration configuration used to build the item stream no longer matches what this match assumes — typically after a gix upgrade or an options change.","triggerScenarios":"Upgrading gix so directory-content emission includes tracked/pruned/ignored entries under some option combinations; changing untracked-files mode or ignore handling in the status options passed into this walker; enabling directory collapse in traversal.","commonSituations":"Dependency bumps of gix in the GitButler workspace; local experiments toggling `gix::status` options; platforms where traversal defaults differ.","solutions":["Revert or pin the gix version whose status emission matches the walker's expectations.","Re-check the status configuration feeding this loop (untracked matching mode, ignore/prune emission flags) and restore the original settings.","If the new behavior is desired, handle those entries explicitly (skip tracked/pruned/ignored) instead of `unreachable!`, with a regression test."],"exampleFix":"// before\n) => {\n    unreachable!(\"we never return these as the status iteration is configured accordingly\")\n}\n\n// after\n) => {\n    // defensive: these are filtered by the configured iteration; skip if ever emitted\n    continue; // or push nothing for this entry\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// skip entries the configured iteration promises never to emit\nfn emitted_by_config(status: &gix::dir::entry::Status) -> bool {\n    !matches!(\n        status,\n        gix::dir::entry::Status::Tracked\n            | gix::dir::entry::Status::Pruned\n            | gix::dir::entry::Status::Ignored(_)\n    )\n}","tryCatchPattern":null,"preventionTips":["After any gix bump, run the worktree-diff snapshot tests before merging.","Keep status options (untracked matching mode, ignore emission) pinned in one constructor so walkers and consumers agree.","When experimenting with traversal options, do it on a branch with the diff tests enabled."],"tags":["rust","but-core","gix","status-iteration","internal-invariant","untracked-files"],"backgroundTag":"gix-status-config-mismatch","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}