{"record":{"id":"6c964ea6ecbfd4f3","repo":"jdx/mise","slug":"the-stamp-list-from-host-for-project-has-seque","errorCode":null,"errorMessage":"the stamp list from {host} for {project} has sequence {sequence}, below the {last} already accepted; refusing what may be a rollback","messagePattern":"the stamp list from (.+?) for (.+?) has sequence (.+?), below the (.+?) already accepted; refusing what may be a rollback","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/packslip_stamps.rs","lineNumber":259,"sourceCode":"        bail!(\n            \"{host} published a stamp list for {project} before (sequence {last}) but now answers 404 at {url}; refusing to treat that as no list, since it would drop the yanks that list carried\"\n        );\n    }\n    Ok(())\n}\n\nfn check_sequence_in(\n    dir: &Path,\n    host: &str,\n    project: &str,\n    list: &ReleaseListStatement,\n) -> Result<()> {\n    let mut state = read_state(dir, host)?;\n    let sequence = list.predicate.sequence;\n    if let Some(&last) = state.sequences.get(project)\n        && sequence < last\n    {\n        bail!(\n            \"the stamp list from {host} for {project} has sequence {sequence}, below the {last} already accepted; refusing what may be a rollback\"\n        );\n    }\n    if state.sequences.get(project) != Some(&sequence) {\n        state.sequences.insert(project.to_string(), sequence);\n        write_state(dir, host, &state)?;\n    }\n    Ok(())\n}\n\n/// Fetch and verify every trusted host's list for a project. `None` when\n/// no stampers are configured or the tool trusts its vendor alone. A host\n/// that has no list for the project stamps nothing; one whose list fails\n/// to verify is an error, since silently ignoring it would let a broken\n/// host widen what another admits.\npub(crate) async fn fetch(project: &str, opts: &ToolVersionOptions) -> Result<Option<Stamps>> {\n    if trusts_vendor(opts) {\n        return Ok(None);","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/packslip_stamps.rs#L241-L277","documentation":"Stamp-list sequences must be monotonically non-decreasing per (host, project). If a freshly fetched stamp list carries a sequence below the one already accepted, mise throws rather than risk applying a rolled-back (possibly malicious) list.","triggerScenarios":"check_sequence_in is called with a verified stamp list whose predicate.sequence is lower than the sequence stored in the per-host state file for that project.","commonSituations":"A host rolled back or re-keyed its stamp lists; requests hitting a stale mirror/CDN edge; state previously synced from a newer mirror; intentional host-side reset of sequences.","solutions":["Ensure the host publishes a stamp list with sequence >= the previously accepted one","Refresh from the authoritative host that issued the higher sequence","Clear the per-host stamp state only if the rollback is intentionally trusted","Wait for the host to publish a new higher-sequence list"],"exampleFix":"// before: pinning to a stale mirror\nMISE_PACKSLIP_STAMP_MIRROR=https://stale.example.com/ mise install aqua:org/tool\n// after: use the authoritative host\nmise install aqua:org/tool","handlingStrategy":"validation","validationCode":"let state = read_stamp_state(host)?;\nif let Some(last) = state.sequences.get(project) {\n    let seq = peek_list_sequence(host, project)?;\n    if seq < *last { eprintln!(\"stamp rollback {last} -> {seq}; refresh from authoritative host\"); }\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"refusing what may be a rollback\") => refresh_from_authoritative_host(host, project)?,\n    other => other?,\n}","preventionTips":["Avoid mirrors that may serve stale stamp lists","Don't reset host sequence counters casually","Share per-host state consistently across machines","Verify host-side re-keying procedures bump sequences monotonically"],"tags":["security","packslip","stamps","rollback-protection"],"backgroundTag":"invalid-state-transition","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}