jdx/mise · error · eyre::Report

local action result is invalid

Error message

local action result is invalid: {}

What it means

`LocalActionCache::find` reads the stored JSON for an action digest and strictly validates it: `version` must be 1, the embedded `action` digest must equal the requested key, and the raw file bytes must equal the canonical re-serialization of the parsed result. Any deviation - hand edits, truncation, or a different serialization - makes the entry invalid and the error names the file. The store path self-heals: `store` detects an invalid existing entry and atomically replaces it.

Solutions

  1. Re-store to heal: `LocalActionCache::store` replaces invalid entries via its `replace_invalid` path.
  2. Or delete the named JSON file (or the `action-results/v1` subtree) - the next successful build republishes it.
  3. Do not edit files under the cache root; give each tool version its own cache directory.

Example fix

// before: the invalid entry propagates as an error
let result = actions.find(&action)?;

// after: treat as a miss, then republish to heal
let result = match actions.find(&action) {
    Ok(result) => result,
    Err(_) => None, // recompute
};
let fresh = recompute_result();
actions.store(&fresh)?; // atomically replaces the invalid entry
Defensive patterns

Strategy: fallback

Try / catch

let result = match actions.find(&action) {
    Ok(result) => result,
    Err(err) => {
        warn!("invalid action result, treating as miss: {err}");
        None
    }
};
// recompute on None, then actions.store(&fresh) heals the invalid entry atomically

Prevention

When it happens

Trigger: Reading an action-result JSON that changed after publishing: manual edits, a partial write from a crash in a pre-atomic version, tools that reformat the cache, or a cache directory shared with another version whose canonical JSON differs.

Common situations: Users inspecting or pretty-printing cache files; mixed-version cache directories; disk-cleanup tools truncating files.

Related errors


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

Appendix: source

Thrown at crates/mise-cache-core/src/local.rs:196

        }
        Ok(self
            .root
            .join("action-results/v1")
            .join(&action.algorithm)
            .join(&action.hash[..2])
            .join(format!("{}-{}.json", action.hash, action.size)))
    }

    /// Find and strictly validate a canonical action result.
    pub fn find(&self, action: &CacheDigest) -> Result<Option<RemoteActionResult>> {
        let path = self.path_for(action)?;
        if !path.exists() {
            return Ok(None);
        }
        let bytes = fs::read(&path)?;
        let result: RemoteActionResult = serde_json::from_slice(&bytes)?;
        if result.version != 1 || result.action != *action || canonical_json(&result)? != bytes {
            bail!("local action result is invalid: {}", path.display());
        }
        Ok(Some(result))
    }

    /// Atomically publish an action result after validating all referenced objects.
    pub fn store(&self, result: &RemoteActionResult) -> Result<PathBuf> {
        if result.version != 1 {
            bail!("unsupported local action result version");
        }
        for digest in [
            Some(&result.action),
            result.metadata.as_ref(),
            result.output_root.as_ref(),
        ]
        .into_iter()
        .flatten()
        {
            if self.cas.find(digest)?.is_none() {

View on GitHub (pinned to 6f52dcdf99)