jdx/mise · error · eyre::Report

cached rustc output set does not match the invocation

Error message

cached rustc output set does not match the invocation

What it means

validated_outputs() requires the cached directory.files count to equal the number of outputs the current invocation expects (emitted files plus the dep-info file) (src/cache/rustc.rs:557-559). A count mismatch means the cached entry does not describe this invocation's output set — the action digest and the stored directory disagree, which in practice means cross-version cache pollution or a tampered/poisoned entry; the restore is refused rather than partially applied.

Source

Thrown at src/cache/rustc.rs:558

        bail!("cached rustc output directory has unsupported entries");
    }
    let mut expected = outputs
        .files
        .iter()
        .chain(std::iter::once(&outputs.dep_info))
        .map(|path| {
            let name = path
                .file_name()
                .and_then(|name| name.to_str())
                .ok_or_else(|| eyre::eyre!("expected rustc output name is not UTF-8"))?;
            if path.parent() != Some(outputs.directory.as_path()) {
                bail!("expected rustc output escapes its output directory");
            }
            Ok((name.to_string(), path.clone()))
        })
        .collect::<Result<BTreeMap<_, _>>>()?;
    if directory.files.len() != expected.len() {
        bail!("cached rustc output set does not match the invocation");
    }
    let mut files = Vec::with_capacity(directory.files.len());
    for node in directory.files {
        validate_file_mode(&node)?;
        let destination = expected
            .remove(&node.name)
            .ok_or_else(|| eyre::eyre!("cached rustc output is unexpected: {}", node.name))?;
        files.push((node, destination));
    }
    if !expected.is_empty() {
        bail!("cached rustc output set is incomplete");
    }
    Ok(files)
}

fn compiler_identity(rustc: &OsStr) -> Result<CompilerIdentity> {
    let executable = resolve_executable(rustc)?;
    let environment = ["RUSTUP_HOME", "RUSTUP_TOOLCHAIN"]

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Purge the affected cache/namespace and rebuild from a single trusted mise version
  2. Keep one mise version per namespace and keep namespaces private per project/team
  3. If it persists on a private cache with matched versions, investigate integrity — this guard exists to block poisoned entries from being restored
Defensive patterns

Strategy: fallback

Validate before calling

fn output_count_matches(directory: &CacheDirectory, outputs: &RustcOutputs) -> bool {
    directory.files.len() == outputs.files.len() + 1 // + dep-info
}

Try / catch

Refuse partial restores: on any set mismatch, discard the cached entry entirely and recompile — never merge cached files with locally produced ones.

Prevention

When it happens

Trigger: A stored CacheDirectory with extra or missing file nodes relative to the invocation's expected outputs: a remote cache shared across mise versions whose output-set parsing differs (e.g. dep-info handling changed), or a deliberately crafted entry aimed at the CAS.

Common situations: Mixed mise versions writing one remote namespace; shared CI caches across teams on different versions; a compromised or untrusted remote cache.

Related errors


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