jdx/mise · error

each version token has one matching kind

Error message

each version token has one matching kind

What it means

In `tokens()`, after the version-token regex matches, the code finds the first capture group that participated and expects one to exist (`.expect("each version token has one matching kind")`). Since the whole pattern is a single alternation, exactly one alternative matches; a panic means a match was produced with zero participating groups — a logic error in the regex structure.

Solutions

  1. Keep the `kinds` array length and order aligned with the regex capture groups
  2. Add a test asserting group-count == kinds.len() so desync is caught in CI
  3. Ensure the outer group wraps the entire alternation so every match populates one kind group

Example fix

// before
let kinds = [Alpha, Beta, Pre]; // fewer kinds than groups
// after
let kinds = [Alpha, Beta, Pre, Rc, Patch, Post, Number, Word]; // matches 8 groups
Defensive patterns

Strategy: validation

Validate before calling

assert_eq!(PATTERN.captures_len() - 1, kinds.len(), "regex groups must match kinds");

Prevention

When it happens

Trigger: `tokens()` matching a version substring where `captures.get(index + 1)` returns None for all kind groups (src/system/packages/brew/cask/app_version.rs:257) — possible only if the regex is edited so a match can occur without any alternative group, or the kinds array is misaligned with the group count.

Common situations: Refactoring the regex (adding/removing groups) without keeping the `kinds` array in sync; a nested/optional group that matches empty and shadows the real alternative.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

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

        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)| {
                    captures
                        .get(index + 1)
                        .map(|matched| (*kind, matched.as_str()))
                })
                .expect("each version token has one matching kind");
            Token { kind, text }
        })
        .collect()
}

/// Compares bundle versions using Homebrew token ordering rather than semver.
///
/// Returns `None` for blank inputs or unequal dot-separated component counts,
/// ignoring trailing dots. Homebrew treats those forms as incomparable rather
/// than padding their components. Comparable `HEAD` versions sort above releases.
pub(super) fn compare_app_versions(first: &str, second: &str) -> Option<Ordering> {
    let dot_count = |value: &str| {
        let value = value.trim_end_matches('.');
        if value.is_empty() {
            0
        } else {
            value.split('.').count()
        }

View on GitHub (pinned to 533346cc37)