jdx/mise · error
lockfile generation would downgrade recorded provenance…
Error message
lockfile generation would downgrade recorded provenance; previous files were preserved
What it means
mise's lockfile records cryptographic provenance (e.g. SLSA attestations) for each locked artifact. During `lockfile generate`, `ensure_no_downgrade` compares the existing recorded provenance with the newly computed one; if the new provenance is weaker or absent (including the packslip-signer-replaces-provenance case), generation aborts so previously written lockfiles are preserved untouched. This is a trust-safety guard, not a bug.
Solutions
- Check why the new provenance is weaker: verify the packslip manifest/attestations are still published for the target version
- Re-enable attestation settings (e.g. `github_attestations`) that were disabled in settings.toml
- Regenerate with the backend that produced the original provenance (e.g. packslip:) instead of a fallback backend
- If the downgrade is intentional, delete/review the existing lockfile entry first so generation starts from a clean trusted state
Example fix
# before: attestations disabled, regeneration downgrades provenance [settings.ruby] github_attestations = false # after [settings.ruby] github_attestations = true
Defensive patterns
Strategy: validation
Validate before calling
let old = existing_entry.provenance.as_ref();
let new = computed_entry.provenance.as_ref();
if new.is_none() || new.map(|n| n.kind()) != old.map(|o| o.kind()) {
// provenance would be downgraded — regenerate with attesting backend first
} Prevention
- Keep attestation settings (github_attestations) enabled consistently across environments
- Always regenerate lockfiles with the same backend that produced the original provenance
- Don't disable attestations in CI before regenerating lockfiles
- Review lockfile provenance fields after backend or registry changes
When it happens
Trigger: Running lockfile generation (`mise lock` / internal `generate`) for a tool whose existing lockfile entry has provenance (or a packslip signer) recorded, but the regenerated entry's provenance is missing or weaker per `provenance_is_downgrade` — e.g. the backend stopped serving attestations, the packslip manifest no longer includes them, or settings for attestations were disabled.
Common situations: Regenerating a lockfile after a registry/backend change dropped attestation data; switching a backend from packslip to a non-attesting backend; CI regenerating lockfiles after attestations were temporarily unavailable upstream; toggling `github_attestations` settings off.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- lockfile generation would downgrade additional artifact…
- {error}
- lockfile generation would change the recorded signer…
- lockfile requires Ruby provenance but GitHub attestations…
- Python locks require credential-free HTTP artifact URLs…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/7e80a9afb266cd73.
Report an issue: GitHub.
Appendix: source
Thrown at src/lockfile/generate.rs:783
lockfile.set_uv_lock(&ba.short, &tv.version, &backend_name, &options, graph)?;
}
Ok(())
}
fn ensure_no_downgrade(old: &PlatformInfo, new: &PlatformInfo, backend: &str) -> Result<()> {
// A verified Packslip signer is the replacement trust baseline for an
// artifact authenticated by its signed release manifest. Older incremental
// lock updates could carry detected GitHub provenance into a Packslip entry,
// but complete generation intentionally does not persist that unverified
// link. Without a signer, retain the ordinary provenance ratchet.
let packslip_signer_replaces_provenance =
backend.starts_with("packslip:") && new.signer.is_some();
if provenance_is_downgrade(
old.provenance.as_ref(),
new.provenance.as_ref(),
packslip_signer_replaces_provenance,
) {
bail!(
"lockfile generation would downgrade recorded provenance; previous files were preserved"
);
}
if let Some(signer) = &old.signer
&& (new.signer.as_ref() != Some(signer) || new.attested_by != old.attested_by)
{
bail!(
"lockfile generation would change the recorded signer; previous files were preserved"
);
}
// Preserve identities across reordering, then pair replaced URLs in their
// configured order so version upgrades retain the previous trust baseline.
let mut replacements = new.additional_artifacts.iter().filter(|artifact| {
!old.additional_artifacts
.iter()
.any(|old| old.url == artifact.url)
});
for artifact in &old.additional_artifacts {View on GitHub (pinned to 533346cc37)