jdx/mise · error

the release list of packslip:{project} has sequence {sequenc

Error message

the release list of packslip:{project} has sequence {sequence}, but sequence {last} was already accepted; refusing to go back

What it means

mise caches the highest release-list sequence number it has ever accepted for each packslip project in a pins file. If a later fetched release list carries a sequence number lower than the cached one, this error is thrown because accepting it could roll back to an outdated or attacker-supplied list.

Source

Thrown at src/packslip_pins.rs:213

        pins.pins.insert(project.to_string(), updated.clone());
        save(path, &pins)?;
    }
    Ok(updated)
}

/// Refuse a release list whose sequence is below one already accepted for
/// the project, and remember the highest seen.
pub(crate) fn check_sequence(project: &str, sequence: u64) -> Result<()> {
    check_sequence_at(&pins_file(), project, sequence)
}

pub(crate) fn check_sequence_at(path: &Path, project: &str, sequence: u64) -> Result<()> {
    let _lock = locked(path)?;
    let mut pins = load(path)?;
    if let Some(last) = pins.sequences.get(project).copied()
        && sequence < last
    {
        bail!(
            "the release list of packslip:{project} has sequence {sequence}, but sequence {last} was already accepted; refusing to go back"
        );
    }
    if pins.sequences.get(project) != Some(&sequence) {
        pins.sequences.insert(project.to_string(), sequence);
        save(path, &pins)?;
    }
    Ok(())
}

/// An absent supplementary list is allowed only before this machine has
/// accepted one. Its disappearance must not undo signed withdrawals.
pub(crate) fn check_missing_list(project: &str) -> Result<()> {
    check_missing_list_at(&pins_file(), project)
}

fn check_missing_list_at(path: &Path, project: &str) -> Result<()> {
    let _lock = locked(path)?;

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Update the registry's signed release list to a sequence number >= the locally accepted one
  2. Refresh from the canonical host that published the higher-sequence list
  3. Delete the pins file entry to re-baseline (only if you trust the lower list, e.g. intentional registry reset)
  4. Wait for the registry to publish a new list with a higher sequence

Example fix

// before: mixing a stale mirror with a newer canonical list
MISE_PACKSLIP_MIRROR=https://stale-mirror.example.com/ mise install aqua:org/tool
// after: use the canonical host that has the highest sequence
mise install aqua:org/tool
Defensive patterns

Strategy: validation

Validate before calling

let pins = read_pins_file()?;
if let Some(last) = pins.sequences.get(project) {
    let seq = fetch_list_sequence(project)?;
    if seq < *last { eprintln!("list would roll back {last} -> {seq}; refresh mirror first"); }
}

Try / catch

match result {
    Err(e) if e.to_string().contains("refusing to go back") => refresh_from_canonical_host(),
    other => other?,
}

Prevention

When it happens

Trigger: Calling packslip release-list verification (via check_sequence -> check_sequence_at) when the remote list's sequence number is lower than the value stored in the local pins file for that project.

Common situations: A registry downgraded or replaced its signed release list; a mirror is serving a stale cached list; the local pins file was populated from a newer mirror earlier; a compromised CDN serves an older signed manifest.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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