jdx/mise · error

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

Error message

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

What it means

When resolving a checkpoint reference by UUID prefix, more than one stored entry may share that prefix. Because the tool cannot know which one is intended, it refuses and asks for a longer prefix that narrows to exactly one match. This is standard short-hash ambiguity handling, mirroring git's behavior.

Source

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

        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 afd2eddd3a)

Solutions

  1. Repeat the command with more characters of the UUID until it's unique.
  2. Use the full UUID from `mise dot log` to be unambiguous.
  3. In scripts, resolve the full ID once and reuse it instead of a short prefix.
  4. If two checkpoints really are duplicates of the same state, prune one from history.

Example fix

// before
let id = resolve_checkpoint("a")?; // ambiguous
// after
let full = list_checkpoints()?.iter().find(|c| c.checkpoint.uuid.starts_with("a")).unwrap().checkpoint.uuid.clone();
let id = resolve_checkpoint(&full)?;
Defensive patterns

Strategy: validation

Validate before calling

let hits: Vec<_> = list_checkpoints()?.into_iter().filter(|c| c.checkpoint.uuid.starts_with(prefix)).collect();
if hits.len() > 1 {
    eprintln!("prefix {prefix:?} is ambiguous; use a longer prefix or the full uuid");
}

Try / catch

match resolve_checkpoint(prefix) {
    Ok(id) => use(id),
    Err(e) if e.to_string().contains("matches more than one checkpoint") => {
        eprintln!("extend the prefix; candidates listed in `mise dot log`");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the checkpoint-resolution API with a short prefix (often 1-2 characters) that matches two or more checkpoint UUIDs in the store.

Common situations: Using a very short prefix in a store with many checkpoints; scripting with a fixed-length prefix assumption that breaks as history grows.

Related errors


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