{"record":{"id":"3cc56874fbc09962","repo":"GitoxideLabs/gitoxide","slug":"just-added","errorCode":null,"errorMessage":"just added","messagePattern":"just added","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-attributes/src/search/attributes.rs","lineNumber":64,"sourceCode":"    /// Update `collection` with newly added attribute names.\n    /// If a `root` is provided, it's not considered a global file anymore.\n    /// If `allow_macros` is `true`, macros will be processed like normal, otherwise they will be skipped entirely.\n    /// Returns `true` if the file was added, or `false` if it didn't exist.\n    pub fn add_patterns_file(\n        &mut self,\n        source: PathBuf,\n        follow_symlinks: bool,\n        root: Option<&Path>,\n        buf: &mut Vec<u8>,\n        collection: &mut MetadataCollection,\n        allow_macros: bool,\n    ) -> std::io::Result<bool> {\n        // TODO: should `Pattern` trait use an instance as first argument to carry this information\n        //       (so no `retain` later, it's slower than skipping)\n        let was_added =\n            gix_glob::search::add_patterns_file(&mut self.patterns, source, follow_symlinks, root, buf, Attributes)?;\n        if was_added {\n            let last = self.patterns.last_mut().expect(\"just added\");\n            if !allow_macros {\n                last.patterns\n                    .retain(|p| !matches!(p.value, Value::MacroAssignments { .. }));\n            }\n            collection.update_from_list(last);\n        }\n        Ok(was_added)\n    }\n    /// Add patterns as parsed from `bytes`, providing their `source` path and possibly their `root` path, the path they\n    /// are relative to. This also means that `source` is contained within `root` if `root` is provided.\n    /// If `allow_macros` is `true`, macros will be processed like normal, otherwise they will be skipped entirely.\n    pub fn add_patterns_buffer(\n        &mut self,\n        bytes: &[u8],\n        source: PathBuf,\n        root: Option<&Path>,\n        collection: &mut MetadataCollection,\n        allow_macros: bool,","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-attributes/src/search/attributes.rs#L46-L82","documentation":"This panic comes from an `.expect(\"just added\")` on `self.patterns.last_mut()` inside `add_patterns_file`. The invariant is that `add_patterns_file` returned `was_added == true`, which by contract means it just pushed a new pattern list onto `self.patterns`, so the last element must exist. The panic indicates the push/return contract of `gix_glob::search::add_patterns_file` was violated.","triggerScenarios":"Calling `Search::add_patterns_file` when `gix_glob::search::add_patterns_file` reports it added a list but the mutable borrow state is inconsistent — practically only reachable if the glob crate's add_patterns_file returns true without actually pushing, or if the patterns vec was concurrently/alienly mutated between the call and `last_mut()`.","commonSituations":"Effectively never hit by library users; it surfaces as a bug report when a mismatched version of `gix-glob` is vendored/patched and its `add_patterns_file` contract diverges from what `gix-attributes` expects.","solutions":["Update `gix-glob` and `gix-attributes` to matching released versions from the same workspace release","Check for patched/vendor overrides of `gix-glob` in Cargo.toml [patch] sections and remove or update them","Report the panic upstream with a repro of the attribute file being loaded","As a workaround, load attribute patterns via `add_patterns_buffer` with manually read file contents"],"exampleFix":"// before (patched gix-glob with wrong contract)\nfn add_patterns_file(...) -> io::Result<bool> { Ok(true) }\n// after: use matched upstream versions\n[dependencies]\ngix-glob = \"=0.17\"\ngix-attributes = \"=0.22\"","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Rust panics cannot be caught per-call without a wrapper\nlet result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    search.add_patterns_file(source, follow, root, buf, &mut collection, true)\n}));\nif let Err(panic) = result { /* downgrade to an error / report bug */ }","preventionTips":["Keep all gix-* crates on versions from the same release","Avoid [patch] overrides of gix-glob","Load attribute files via buffer APIs if you need full control"],"tags":["rust","panic","internal-invariant","attributes"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}