jdx/mise · error

installation failed; previous lockfiles were preserved

Error message

installation failed; previous lockfiles were preserved

What it means

The no-detail variant of ensure_install_succeeded: mise knows the install failed (INSTALL_FAILED flag set) but no detailed error text was captured, so it reports the generic message that installation failed and the previous lockfiles were preserved. Existing lockfiles were deliberately not overwritten, so your pinned state is safe.

Solutions

  1. Rerun `mise lock`/`mise install` with MISE_DEBUG=1 to capture the underlying failure cause.
  2. Verify network access and the tool backend (registry reachable, token valid).
  3. Since lockfiles are preserved, retry freely; remove or change the failing tool request if it consistently fails.
Defensive patterns

Strategy: retry

Try / catch

if ! mise lock; then MISE_DEBUG=1 mise lock; fi  # retry with debug to surface the hidden cause

Prevention

When it happens

Trigger: Tool installation fails during lockfile generation without a recorded failure detail (e.g. an early abort path that sets the flag but not INSTALL_FAILURE_DETAIL); rerunning after a failed generate when the failure cause was cleared.

Common situations: Aborted installs (Ctrl-C mid-install during `mise lock`); backend failures on code paths that do not attach detail; CI runs where the install step died unexpectedly.

Related errors


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

Appendix: source

Thrown at src/lockfile/generate.rs:127

                    .collect::<Vec<_>>()
                    .join("\n"),
            );
            record_install_failure();
        }
        errors
    }
}

pub(crate) fn record_install_failure() {
    INSTALL_FAILED.store(true, Ordering::Relaxed);
}

pub(crate) fn ensure_install_succeeded() -> Result<()> {
    if INSTALL_FAILED.load(Ordering::Relaxed) {
        if let Some(detail) = INSTALL_FAILURE_DETAIL.lock().unwrap().as_ref() {
            bail!("{detail}\nprevious lockfiles were preserved");
        }
        bail!("installation failed; previous lockfiles were preserved");
    }
    Ok(())
}

pub(crate) fn has_previous_file(config: &Config, path: &Path) -> bool {
    path.exists()
        || monorepo_lockfile_migration_paths(config)
            .iter()
            .any(|(source, target)| target == path && source.exists())
}

pub(crate) fn read_previous(config: &Config, path: &Path, upgrade: bool) -> Result<Lockfile> {
    let mut previous = Lockfile::read(path)?;
    let mut exists = path.exists();
    for (source, target) in monorepo_lockfile_migration_paths(config) {
        if target != path || !source.exists() {
            continue;
        }

View on GitHub (pinned to 533346cc37)