jdx/mise · error · eyre::Report

automatic cross-platform provisioning refuses to replace a c

Error message

automatic cross-platform provisioning refuses to replace a custom mise build with an official binary because {} does not match the signed mise {} release checksums; set mise_bin, remote_mise, or bootstrap_command

What it means

Thrown by RemoteArtifactResolver::ensure_official_local on a release build when the local mise binary's SHA-256 does not match any checksum for the local OS/arch assets in the signed SHASUMS256.txt manifest. Automatic cross-platform provisioning refuses to run from a binary it cannot prove is the official release, because the flow's security model is 'a signed official binary may fetch other signed official binaries'. Any locally compiled release build, distro-repackaged binary, patched/stripped binary, or corrupted file fails this gate.

Source

Thrown at src/system/remote.rs:1043

            return Ok(());
        }
        if cfg!(debug_assertions) {
            bail!(
                "automatic cross-platform provisioning is unavailable from a debug mise build; set mise_bin, remote_mise, or bootstrap_command"
            );
        }
        let local_os = normalize_os(std::env::consts::OS);
        let local_arch = normalize_arch(std::env::consts::ARCH);
        let candidates = official_release_assets(&local_os, &local_arch)?;
        let actual = crate::hash::file_hash_sha256(local, None)?;
        let manifest = self.manifest().await?;
        let official = candidates.iter().any(|asset| {
            manifest
                .checksum(asset)
                .is_ok_and(|expected| expected.eq_ignore_ascii_case(&actual))
        });
        if !official {
            bail!(
                "automatic cross-platform provisioning refuses to replace a custom mise build with an official binary because {} does not match the signed mise {} release checksums; set mise_bin, remote_mise, or bootstrap_command",
                local.display(),
                env!("CARGO_PKG_VERSION")
            );
        }
        self.official_local_verified = true;
        Ok(())
    }

    async fn manifest(&mut self) -> Result<&ReleaseManifest> {
        if self.manifest.is_none() {
            let manifest_url = release_url("SHASUMS256.txt");
            let signature_url = release_url("SHASUMS256.txt.minisig");
            let (contents, signature) = tokio::try_join!(
                HTTP.get_text_cached(&manifest_url),
                HTTP.get_text_cached(&signature_url)
            )
            .wrap_err_with(|| {

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Set mise_bin on the host entry to upload that exact custom binary instead of the official artifact
  2. Set remote_mise or bootstrap_command to provision mise on the remote without involving the official artifact flow
  3. Or run the genuine official mise release for CARGO_PKG_VERSION so the checksum matches

Example fix

# before (mise.toml)
[bootstrap.remote.hosts.builder]
host = "builder@aarch64-runner"

# after
[bootstrap.remote.hosts.builder]
host = "builder@aarch64-runner"
mise_bin = "./target/release/mise"  # upload this custom build explicitly
Defensive patterns

Strategy: fallback

Validate before calling

# Pre-check before relying on automatic provisioning from a custom build:
# the sha256 of your binary must equal the entry in the signed SHASUMS256.txt
V=$(mise --version | awk '{print $2}')
MYHASH=$(sha256sum "$(command -v mise)" | cut -d' ' -f1)
curl -fsSL "https://github.com/jdx/mise/releases/download/v${V}/SHASUMS256.txt" \
  | grep -qi "^${MYHASH}" || echo "custom build: set mise_bin/remote_mise/bootstrap_command"

Type guard

fn is_official_release_binary(local: &Path, manifest: &ReleaseManifest) -> bool {
    let Ok(actual) = crate::hash::file_hash_sha256(local, None) else {
        return false;
    };
    official_release_assets(&normalize_os(std::env::consts::OS), &normalize_arch(std::env::consts::ARCH))
        .map(|assets| {
            assets.iter().any(|a| {
                manifest.checksum(a).is_ok_and(|c| c.eq_ignore_ascii_case(&actual))
            })
        })
        .unwrap_or(false)
}

Try / catch

match resolver.resolve(&platform, &local).await {
    Err(e) if e.to_string().contains("does not match the signed mise") => {
        // deliberate fallback: upload the custom binary explicitly
        upload_custom_binary(&host, &local).await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running mise built with cargo build --release (byte-different from the official artifact), a distribution package build, a forked/patched mise, or a binary from a version whose local-arch asset name/checksum is not in the manifest, while reaching automatic artifact resolution (remote platform differs from local, no mise_bin/remote_mise/bootstrap_command set).

Common situations: Companies building internal mise forks; packagers testing remote bootstrap; users who rebuilt mise with different toolchain flags (different codegen = different hash); cached manifest vs newer binary version mismatch.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/f26066ea498e3e59. Report an issue: GitHub.