{"record":{"id":"e49cd786273fa142","repo":"GitoxideLabs/gitoxide","slug":"initialized","errorCode":null,"errorMessage":"initialized","messagePattern":"initialized","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-attributes/src/search/outcome.rs","lineNumber":232,"sourceCode":"    }\n}\n\nimpl Outcome {\n    /// Given a list of `attrs` by order, return true if at least one of them is not set\n    pub(crate) fn has_unspecified_attributes(&self, mut attrs: impl Iterator<Item = AttributeId>) -> bool {\n        attrs.any(|order| self.matches_by_id[order.0].r#match.is_none())\n    }\n    /// Return the amount of attributes haven't yet been found.\n    ///\n    /// If this number reaches 0, then the search can be stopped as there is nothing more to fill in.\n    pub(crate) fn remaining(&self) -> usize {\n        self.remaining\n            .expect(\"BUG: instance must be initialized for each search set\")\n    }\n\n    fn reduce_and_check_if_done(&mut self, attr: AttributeId) -> bool {\n        if self.selected.is_empty() || self.selected.iter().any(|(_name, id)| *id == Some(attr)) {\n            *self.remaining.as_mut().expect(\"initialized\") -= 1;\n        }\n        self.is_done()\n    }\n}\n\nimpl std::fmt::Debug for Outcome {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        struct AsDisplay<'a>(&'a dyn std::fmt::Display);\n        impl std::fmt::Debug for AsDisplay<'_> {\n            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n                self.0.fmt(f)\n            }\n        }\n\n        let mut dbg = f.debug_tuple(\"Outcome\");\n        if self.selected.is_empty() {\n            for match_ in self.iter() {\n                dbg.field(&AsDisplay(&match_.assignment));","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-attributes/src/search/outcome.rs#L214-L250","documentation":"`reduce_and_check_if_done` decrements the optional `remaining` counter with `.expect(\"initialized\")` for each attribute matched. Like the sibling `remaining()`, this panics if the Outcome was never initialized for a search set when `fill_attributes` starts matching attributes.","triggerScenarios":"Invoking the attribute matching pipeline (`fill_attributes`) with an Outcome whose `remaining` field is still `None` — i.e. the instance skipped the initialization step that assigns `remaining` from the selected attribute count.","commonSituations":"Hand-rolled integrations of `gix-attributes` search that construct Outcome directly; stale Outcome reuse across searches.","solutions":["Always let the search API create/initialize the Outcome before calling fill-style APIs","Call the collection's initialization for the selected attribute set before matching","Re-create the Outcome per search set; never reuse across searches","Update gix-attributes to a version where initialization is enforced by construction"],"exampleFix":"// before\nlet mut outcome = Outcome::default();\nfill_attributes(&mut outcome, ...);\n// after\nlet mut outcome = collection.selected_attribute_set(...); // initializes remaining\nfill_attributes(&mut outcome, ...);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":null,"tryCatchPattern":"let done = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    fill_attributes(&mut outcome, ...)\n}));","preventionTips":["Initialize the Outcome with the selected attribute set before matching","Use only the high-level gix attributes APIs that manage initialization"],"tags":["rust","panic","uninitialized-state","attributes"],"backgroundTag":"invalid-state-transition","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"}