{"record":{"id":"d41e6382e91f0042","repo":"stamparm/maltrail","slug":"lookahead-should-match","errorCode":null,"errorMessage":"lookahead should match","messagePattern":"lookahead should match","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"sensor/src/pyre.rs","lineNumber":364,"sourceCode":"        // a leading flag group is fine, and scoped flags are fine anywhere\n        assert!(!has_late_global_flags(r\"(?i)abc\"));\n        assert!(!has_late_global_flags(r\"a(?i:b)c\"));\n        assert!(!has_late_global_flags(r\"a(?P<n>b)c\"));\n        assert!(!has_late_global_flags(r\"a(?!b)c\"));\n        assert!(!has_late_global_flags(r\"a\\(?i\\)b\"));\n    }\n\n    #[test]\n    fn punctuation_escapes_the_crate_dislikes_still_compile() {\n        // from data/ua.txt: Python treats \\> as a literal '>'\n        let re = build(r\"<script src=[^\\>]*>\").unwrap();\n        assert!(re.is_match(\"<script src=x>\"));\n    }\n\n    #[test]\n    fn fancy_handles_lookahead() {\n        let re = build_fancy(r\"(?P<high>malware(?! (distribution|site)))|(?P<low>reputation)\").unwrap();\n        let hit = re.captures(\"known malware c2\").unwrap().expect(\"lookahead should match\");\n        assert!(hit.name(\"high\").is_some());\n        // the negative lookahead suppresses the match entirely here\n        assert!(matches!(re.captures(\"malware distribution\"), Ok(None)));\n        assert!(re.captures(\"reputation x\").unwrap().unwrap().name(\"low\").is_some());\n    }\n}\n","sourceCodeStart":346,"sourceCodeEnd":371,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/sensor/src/pyre.rs#L346-L371","documentation":"In the fancy-regex engine test `fancy_handles_lookahead`, `re.captures(...)` returns `Result<Option<Captures>>` and the test `.unwrap()`s the `Result` then `.expect(\"lookahead should match\")`s the `Option`. The panic asserts the pattern `(?P<high>malware(?! (distribution|site)))|(?P<low>reputation)` matches 'known malware c2' via the `high` group; failure means the engine no longer handles named-group alternation with negative lookahead.","triggerScenarios":"`build_fancy(...).captures(\"known malware c2\")` returns `Ok(None)` (no match) or `Err` (regex compile/exec error), panicking at the expect. Triggered by regressions in the fancy regex backend: broken negative-lookahead semantics (over-suppressing), named-capture alternation bugs, or `build_fancy` compiling the pattern incorrectly.","commonSituations":"Upgrading or swapping the regex engine backing `build_fancy`; changes to the lookahead lowering/compilation; pattern-rewrite logic that mangles `(?P<name>...)` groups inside alternations; test refactor altering the sample text.","solutions":["First test the pattern with a standalone fancy-regex instance (`Regex::new` + `captures`) to isolate whether the bug is in the engine or in `build_fancy`'s pattern rewriting.","Print the rewritten pattern from `build_fancy` and verify the named groups and `(?! ...)` lookahead survive translation intact.","Check the engine version's lookahead support; if the backend changed, fix lowering of negative lookahead so a non-matching suffix does not suppress the whole alternation branch.","Split the test: assert `is_match` before asserting group captures, so match-failure and group-extraction regressions are distinguishable."],"exampleFix":"// before\nlet hit = re.captures(\"known malware c2\").unwrap().expect(\"lookahead should match\");\n// after (diagnose which stage failed)\nlet hit = re.captures(\"known malware c2\")\n    .expect(\"captures returned Err\")\n    .unwrap_or_else(|| panic!(\"no match for 'known malware c2' with pattern {}\", re.as_str()));","handlingStrategy":"validation","validationCode":"// verify the pattern compiles and matches before asserting groups\nassert!(re.is_match(\"known malware c2\"), \"pattern lost lookahead semantics\");","typeGuard":null,"tryCatchPattern":"let hit = re.captures(\"known malware c2\")\n    .expect(\"captures Err\")\n    .unwrap_or_else(|| panic!(\"no match; pattern={}\", re.as_str()));","preventionTips":["Split is_match vs captures assertions to localize regressions","Print the rewritten pattern when changing build_fancy","Test negative-lookahead suppression cases next to positive cases","Pin/upgrade the regex engine deliberately and rerun semantics tests"],"tags":["rust","test","regex","lookahead","fancy-regex"],"backgroundTag":"internal-invariant-violation","analyzedSha":"77cfb06d7606506d101bbcec0786c77166c4255e","analyzedAt":"2026-09-13T03:50:16.010Z","contentChangedAt":"2026-09-13T03:50:16.010Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}