jdx/mise · error

invalid checkpoint reference

Error message

invalid checkpoint reference {spec:?}

What it means

When resolving a checkpoint reference, mise first tries to expand a spec to a UUID prefix and then match entries. If after expansion the prefix is empty, there is nothing sensible to match against, so mise rejects the spec as invalid rather than matching every entry. This is an input-validation error for checkpoint selectors.

Solutions

  1. Supply a non-empty checkpoint id or UUID prefix.
  2. List available checkpoints to copy a valid id.
  3. Check shell scripts for unset variables feeding the empty spec.
  4. Quote arguments to avoid the shell stripping them.

Example fix

// before
mise dotfiles checkout "$CKPT"   # CKPT is unset
Error: invalid checkpoint reference ""

// after
CKPT=$(mise dotfiles history list --latest-id)
mise dotfiles checkout "$CKPT"
Defensive patterns

Strategy: validation

Validate before calling

if spec.trim().is_empty() {
  eprintln!("checkpoint reference is empty; run `mise dotfiles history list` for valid ids");
}

Type guard

fn is_valid_checkpoint_spec(spec: &str) -> bool {
  !spec.trim().is_empty()
}

Prevention

When it happens

Trigger: Passing an empty or whitespace-only checkpoint spec (after the non-UUID branch), or a spec that fails the expansion logic leaving an empty prefix, e.g. `mise dotfiles checkout ""`.

Common situations: A shell variable holding the checkpoint id is unset/empty (`$LATEST` empty); quoting mistake passes an empty argument; script automation drops the id.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

                )
            });
    }
    let prefix = if let Some(prefix) = spec.strip_prefix("commit:") {
        prefix
    } else if !spec.is_empty() && spec.bytes().all(|byte| byte.is_ascii_digit()) {
        let id = spec.parse::<u64>().map_err(|_| {
            eyre!("invalid checkpoint ID {spec:?}; use commit:<sha> for a numeric commit hash")
        })?;
        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()

View on GitHub (pinned to 533346cc37)