jdx/mise · error
the release list of packslip
Error message
the release list of packslip:{project} has sequence {sequence}, but sequence {last} was already accepted; refusing to go back What it means
The packslip pins file stores a monotonic sequence number per project representing the release list already accepted. `check_sequence_at` refuses any release list with a sequence lower than the recorded one, preventing rollback attacks where an attacker serves an older (possibly vulnerable) release list. Once a sequence is accepted it cannot go back until the pin is forgotten.
Solutions
- Wait for or force-refresh the upstream release list (bust cache, use the official endpoint) so it serves the current sequence
- Check for a proxy/mirror serving stale manifests and bypass it (unset MISE proxy vars, use direct network)
- Verify the vendor didn't actually roll back their release feed; if genuine and announced, run `mise packslip forget <project>` and reinstall to reset the sequence
- Inspect the pins file location for the recorded sequence to confirm which side is stale
Example fix
// before: stale mirror serves sequence 12 after 13 accepted mise install packslip:example-cli # refusing to go back // after: fetch current list / reset pin if vendor confirmed rollback mise packslip forget example-cli && mise install packslip:example-cli
Defensive patterns
Strategy: retry
Validate before calling
mise packslip status <project> # compare remote release-list sequence with accepted pin
Try / catch
match check_sequence_at(pins_path, project, seq) {
Err(e) if is_stale_cache_error(&e) => { bust_cache(); retry_with_fresh_manifest(); }
Err(e) => return Err(e), // genuine rollback: refuse
Ok(()) => proceed(),
} Prevention
- Avoid caching proxies/CDNs for packslip release lists, or configure short TTLs
- Always fetch the release list from the official endpoint
- If a downgrade is genuinely required (vendor rollback), do `mise packslip forget <project>` explicitly rather than deleting pin files by hand
When it happens
Trigger: Installing/updating a packslip project when the fetched release list's sequence number is less than the highest previously accepted sequence in the pins file — e.g. a mirror serving stale data, a CDN caching an old manifest, or a vendored downgrade.
Common situations: Stale CDN/mirror cache after a vendor re-publish; point-in-time snapshot or proxy serving an older manifest; switching to a frozen vendor feed; restored backup of the pins file alongside a newer upstream (reverse case) or older remote list.
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
- mise.lock says signed , but this release is signed by …
- packslip: : this release . If the vendor announced the…
- the release list in github.com/
- cached rustc output has an unsafe file mode
- published a stamp list for before (sequence ) but now…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/eec1c4942f085426.
Report an issue: GitHub.
Appendix: 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 533346cc37)