{"record":{"id":"e1e823ff0a60bf31","repo":"jdx/mise","slug":"valid-homebrew-version-token-pattern","errorCode":null,"errorMessage":"valid Homebrew version token pattern","messagePattern":"valid Homebrew version token pattern","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/app_version.rs","lineNumber":234,"sourceCode":"}\n\n/// Compares ASCII digit strings without integer overflow, ignoring leading zeros.\n/// Empty strings represent zero.\nfn compare_digits(a: &str, b: &str) -> Ordering {\n    let a = a.trim_start_matches('0');\n    let b = b.trim_start_matches('0');\n    a.len().cmp(&b.len()).then_with(|| a.cmp(b))\n}\n\n/// Extracts numeric, qualifier, and text tokens using Homebrew's version pattern.\n/// Qualifier recognition is case-insensitive; token text retains its original case.\nfn tokens(version: &str) -> Vec<Token<'_>> {\n    static PATTERN: LazyLock<Regex> = LazyLock::new(|| {\n        Regex::new(concat!(\n            \"(?i:(alpha[0-9]*|a[0-9]+)|(beta[0-9]*|b[0-9]+)|(pre[0-9]*)|\",\n            \"(rc[0-9]*)|(p[0-9]*)|(.post[0-9]+)|([0-9]+)|([a-z]+))\"\n        ))\n        .expect(\"valid Homebrew version token pattern\")\n    });\n    let kinds = [\n        TokenKind::Alpha,\n        TokenKind::Beta,\n        TokenKind::Pre,\n        TokenKind::Rc,\n        TokenKind::Patch,\n        TokenKind::Post,\n        TokenKind::Numeric,\n        TokenKind::Text,\n    ];\n    PATTERN\n        .captures_iter(version)\n        .map(|captures| {\n            let (kind, text) = kinds\n                .iter()\n                .enumerate()\n                .find_map(|(index, kind)| {","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/app_version.rs#L216-L252","documentation":"A static `Regex::new(...).expect(\"valid Homebrew version token pattern\")` panic. The pattern is compiled once via `LazyLock`; a panic here can only mean the hard-coded Homebrew version token regex failed to compile — normally impossible unless the source pattern was edited incorrectly.","triggerScenarios":"Calling `tokens()` (via `compare_app_versions`) on any version string the first time, after someone modified the hard-coded regex in src/system/packages/brew/cask/app_version.rs:234 so it is syntactically invalid (e.g. unbalanced groups).","commonSituations":"Editing the regex during development; platform regex-engine differences if the pattern is ported; merging conflicting regex changes.","solutions":["Fix the regex syntax so it compiles (count capture groups, close all parens)","Run a unit test that touches compare_app_versions so compilation happens in CI","Temporarily replace expect with a panic-free constructor during regex experimentation"],"exampleFix":"// before\n\"(?i:(alpha[0-9]*|a[0-9]+|(beta[0-9]*|b[0-9]+)|...\"\n// after\n\"(?i:(alpha[0-9]*|a[0-9]+)|(beta[0-9]*|b[0-9]+)|(pre[0-9]*)|...\"","handlingStrategy":"try-catch","validationCode":"// compile-time-ish check in a test\n#[test] fn token_regex_compiles() {\n    LazyLock::force(&PATTERN);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never edit the static regex without running a test that calls tokens()","Keep capture-group structure documented next to the pattern","Let CI compile the LazyLock via a unit test"],"tags":["panic","regex","homebrew","version-comparison"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}