{"record":{"id":"a4e75ed6d5b8ac8a","repo":"gitbutlerapp/gitbutler","slug":"anchor-is-always-present-in-the-order-at-this-poin","errorCode":null,"errorMessage":"anchor is always present in the order at this point","messagePattern":"anchor is always present in the order at this point","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/but-workspace/src/branch/create_reference.rs","lineNumber":629,"sourceCode":"    /// - [`Position::Above`] takes the anchor's slot, pushing the anchor down; [`Position::Below`]\n    ///   goes right after the anchor. This only affects *ordering* — unlike [`Anchor::AtSegment`],\n    ///   it never changes which branch owns the commit.\n    fn insert_into_branch_stack_order(\n        mut order: Vec<gix::refs::FullName>,\n        anchor: &gix::refs::FullNameRef,\n        new_ref: &gix::refs::FullNameRef,\n        position: Position,\n    ) -> Vec<gix::refs::FullName> {\n        if !order.iter().any(|branch| branch.as_ref() == anchor) {\n            order.push(anchor.to_owned());\n        }\n        order.retain(|branch| branch.as_ref() != new_ref);\n        // `anchor` was pushed above if it was missing, and `retain` only drops `new_ref`, so the\n        // anchor is guaranteed to still be present here.\n        let anchor_idx = order\n            .iter()\n            .position(|branch| branch.as_ref() == anchor)\n            .expect(\"anchor is always present in the order at this point\");\n        let insert_idx = match position {\n            Position::Above => anchor_idx,\n            Position::Below => anchor_idx + 1,\n        };\n        order.insert(insert_idx, new_ref.to_owned());\n        order\n    }\n\n    fn is_not_a_directory_ref_edit_error(err: &gix::reference::edit::Error) -> bool {\n        matches!(\n            err,\n            gix::reference::edit::Error::FileTransactionPrepare(\n                gix::refs::file::transaction::prepare::Error::Io(io_err)\n            ) if io_err.kind() == std::io::ErrorKind::NotADirectory\n        )\n    }\n\n    fn find_colliding_ref_ancestor(","sourceCodeStart":611,"sourceCodeEnd":647,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-workspace/src/branch/create_reference.rs#L611-L647","documentation":"Panic from `expect(\"anchor is always present in the order at this point\")` in `insert_into_order` (but-workspace create_reference.rs:629). The function pushes `anchor` into `order` if missing, then `retain` removes only `new_ref`, so the subsequent `position()` lookup must succeed — the source comment documents exactly this reasoning. It is a locally proven invariant; a panic implies someone changed the push/retain logic so the anchor can be dropped.","triggerScenarios":"Calling branch-order insertion where `anchor == new_ref` combined with a code change that makes retain drop more than `new_ref`; refactors of `insert_into_order` that reorder the push/retain/position steps; only reachable through a modified implementation, not through any input to the shipped one.","commonSituations":"Contributors editing this helper (e.g. adding rename handling that also removes the old anchor name); downstream forks with custom order-filtering; none for stock GitButler users.","solutions":["No caller-side action — the invariant holds in the shipped code","For maintainers editing this function: keep the push-then-retain order, and assert `anchor != new_ref` upstream if renaming becomes possible","Add a unit test covering anchor==new_ref if you touch this logic"],"exampleFix":"// before (fragile after edits)\norder.retain(|branch| branch.as_ref() != new_ref);\nlet anchor_idx = order.iter().position(|b| b.as_ref() == anchor).expect(\"...\");\n\n// after: make the invariant explicit\nif anchor == new_ref { return order; }\nlet Some(anchor_idx) = order.iter().position(|b| b.as_ref() == anchor) else {\n    bail!(\"anchor {anchor} disappeared from branch order\");\n};","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["No input can trigger this in shipped code","Maintainers: keep push-anchor-then-retain order intact and test the anchor==new_ref case when editing insert_into_order"],"tags":["rust","panic","expect","branch-order","invariant","unreachable","gitbutler"],"backgroundTag":"internal-invariant-panic","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}