jdx/mise · error

matches more than one checkpoint; use a longer prefix

Error message

{spec:?} matches more than one checkpoint; use a longer prefix

What it means

Prefix matching for checkpoint references can be ambiguous: if the given prefix matches more than one checkpoint UUID, mise cannot know which entry you mean and refuses to guess. The message asks for a longer prefix to disambiguate. This is the standard short-hash ambiguity error applied to checkpoint ids.

Solutions

  1. Repeat the command with a longer prefix until it is unique.
  2. List checkpoints to copy the full UUID.
  3. In scripts, always pass full ids captured from the list output instead of hand-shortened prefixes.

Example fix

// before
mise dotfiles show ab
Error: "ab" matches more than one checkpoint; use a longer prefix

// after
mise dotfiles show ab3f9c2e
Defensive patterns

Strategy: validation

Validate before calling

let matching: Vec<_> = entries.iter().filter(|e| e.checkpoint.uuid.starts_with(prefix)).collect();
if matching.len() > 1 {
  eprintln!("prefix {prefix} is ambiguous ({} matches); use a longer prefix", matching.len());
}

Type guard

fn prefix_is_unique(prefix: &str, entries: &[Entry]) -> bool {
  entries.iter().filter(|e| e.checkpoint.uuid.starts_with(prefix)).count() == 1
}

Prevention

When it happens

Trigger: Supplying a short UUID prefix that is a prefix of two or more stored checkpoint UUIDs, e.g. `mise dotfiles show abc` when both `abc1...` and `abc9...` exist.

Common situations: Using a 1-3 character prefix from memory; large history where early characters collide; scripting with truncated ids.

Related errors


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

Appendix: source

Thrown at src/system/history/store.rs:1019

        return entries
            .iter()
            .find(|entry| entry.id == id)
            .map(|entry| entry.id)
            .ok_or_else(|| eyre!("no history checkpoint matches {spec:?}"));
    } else {
        spec
    };
    if prefix.is_empty() {
        bail!("invalid checkpoint reference {spec:?}");
    }
    let matches: Vec<&Entry> = entries
        .iter()
        .filter(|entry| entry.checkpoint.uuid.starts_with(prefix))
        .collect();
    match matches.as_slice() {
        [one] => Ok(one.id),
        [] => bail!("no history checkpoint matches {spec:?}"),
        _ => bail!("{spec:?} matches more than one checkpoint; use a longer prefix"),
    }
}

pub(crate) fn now_rfc3339() -> String {
    chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
}

pub(crate) fn new_uuid() -> String {
    uuid::Uuid::now_v7().to_string()
}

pub(crate) fn write_json<T: Serialize>(path: &Path, value: &T) -> Result<()> {
    let mut text = serde_json::to_string_pretty(value)?;
    text.push('\n');
    if let Some(parent) = path.parent() {
        file::create_dir_all(parent)?;
    }
    file::write_atomic(path, text).wrap_err_with(|| format!("writing {}", display_path(path)))?;

View on GitHub (pinned to 533346cc37)