jdx/mise · error

valid Homebrew version token pattern

Error message

valid Homebrew version token pattern

What it means

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.

Solutions

  1. Fix the regex syntax so it compiles (count capture groups, close all parens)
  2. Run a unit test that touches compare_app_versions so compilation happens in CI
  3. Temporarily replace expect with a panic-free constructor during regex experimentation

Example fix

// before
"(?i:(alpha[0-9]*|a[0-9]+|(beta[0-9]*|b[0-9]+)|..."
// after
"(?i:(alpha[0-9]*|a[0-9]+)|(beta[0-9]*|b[0-9]+)|(pre[0-9]*)|..."
Defensive patterns

Strategy: try-catch

Validate before calling

// compile-time-ish check in a test
#[test] fn token_regex_compiles() {
    LazyLock::force(&PATTERN);
}

Prevention

When it happens

Trigger: 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).

Common situations: Editing the regex during development; platform regex-engine differences if the pattern is ported; merging conflicting regex changes.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/e1e823ff0a60bf31. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/cask/app_version.rs:234

}

/// Compares ASCII digit strings without integer overflow, ignoring leading zeros.
/// Empty strings represent zero.
fn compare_digits(a: &str, b: &str) -> Ordering {
    let a = a.trim_start_matches('0');
    let b = b.trim_start_matches('0');
    a.len().cmp(&b.len()).then_with(|| a.cmp(b))
}

/// Extracts numeric, qualifier, and text tokens using Homebrew's version pattern.
/// Qualifier recognition is case-insensitive; token text retains its original case.
fn tokens(version: &str) -> Vec<Token<'_>> {
    static PATTERN: LazyLock<Regex> = LazyLock::new(|| {
        Regex::new(concat!(
            "(?i:(alpha[0-9]*|a[0-9]+)|(beta[0-9]*|b[0-9]+)|(pre[0-9]*)|",
            "(rc[0-9]*)|(p[0-9]*)|(.post[0-9]+)|([0-9]+)|([a-z]+))"
        ))
        .expect("valid Homebrew version token pattern")
    });
    let kinds = [
        TokenKind::Alpha,
        TokenKind::Beta,
        TokenKind::Pre,
        TokenKind::Rc,
        TokenKind::Patch,
        TokenKind::Post,
        TokenKind::Numeric,
        TokenKind::Text,
    ];
    PATTERN
        .captures_iter(version)
        .map(|captures| {
            let (kind, text) = kinds
                .iter()
                .enumerate()
                .find_map(|(index, kind)| {

View on GitHub (pinned to 533346cc37)