{"record":{"id":"d1e6afcc0aecef32","repo":"GitoxideLabs/gitoxide","slug":"pattern-still-present","errorCode":null,"errorMessage":"pattern still present","messagePattern":"pattern still present","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-attributes/src/search/outcome.rs","lineNumber":377,"sourceCode":"}\n\n/// A version of `Match` without references.\n#[derive(Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]\npub struct Match {\n    /// The glob pattern itself, like `/target/*`.\n    pub pattern: RefMapKey,\n    /// The key=value pair of the attribute that matched at the pattern. There can be multiple matches per pattern.\n    pub assignment: RefMapKey,\n    /// Additional information about the kind of match.\n    pub kind: MatchKind,\n    /// Information about the location of the match.\n    pub location: MatchLocation,\n}\n\nimpl Match {\n    fn to_outer<'a>(&self, out: &'a Outcome) -> crate::search::Match<'a> {\n        crate::search::Match {\n            pattern: out.patterns.resolve(self.pattern).expect(\"pattern still present\"),\n            assignment: out\n                .assignments\n                .resolve(self.assignment)\n                .expect(\"assignment present\")\n                .as_ref(),\n            kind: self.kind,\n            location: self.location.to_outer(out),\n        }\n    }\n}\n\n/// A version of `MatchLocation` without references.\n#[derive(Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]\npub struct MatchLocation {\n    /// The path to the source from which the pattern was loaded, or `None` if it was specified by other means.\n    pub source: Option<RefMapKey>,\n    /// The line at which the pattern was found in its `source` file, or the occurrence in which it was provided.\n    pub sequence_number: usize,","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-attributes/src/search/outcome.rs#L359-L395","documentation":"`Match::to_outer` resolves a stored pattern index against the Outcome's arena with `out.patterns.resolve(self.pattern).expect(\"pattern still present\")`. Match results hold indices into the Outcome's pattern arena, so resolution can only fail if the Outcome (or the arenas backing it) was dropped/moved while matches referencing it outlive or bypass it — a lifetime/interning invariant.","triggerScenarios":"Using match results after the underlying search Outcome that owns the pattern storage is no longer intact, or mixing Match values from different Outcome instances; typically prevented by the borrow-bound API, so violations indicate unsafe code or version skew.","commonSituations":"Storing `crate::search::Match` beyond the Outcome's lifetime via unsafe transmutes, or custom code that re-resolves indices against a rebuilt collection.","solutions":["Keep match results used only within the scope of the Outcome that produced them","Never store/resolve match indices across different collection instances","Upgrade gix to get lifetime-bound APIs if you were working around them unsafely","Report with a minimal repro if hit through safe public APIs"],"exampleFix":"// before\nlet matches = { let outcome = do_search(); outcome.matches() }; // outcome dropped\nresolve(matches)\n// after\nlet outcome = do_search();\nlet matches = outcome.matches(); // use while outcome is alive\nresolve(matches)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn matches_alive<'a>(m: &[gix_attributes::search::Match<'a>], _out: &'a Outcome) -> bool { true } // rely on the borrow checker instead of unsafe","tryCatchPattern":"std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| match.to_outer(&outcome)));","preventionTips":["Consume matches within the Outcome's scope","Never transmute or store matches beyond their lifetime","Avoid unsafe code around gix-attributes internals"],"tags":["rust","panic","lifetime","internal-invariant"],"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"}