jdx/mise · error · eyre::Report

cannot publish an action result with a missing blob

Error message

cannot publish an action result with a missing blob

What it means

`LocalActionCache::store` requires every digest referenced by the result - the action digest itself plus optional `metadata` and `output_root` - to already exist and verify in the local CAS before the index entry is published. Publishing without the blobs would create dangling references. The crate's own test (`publishes_action_results_after_referenced_blobs`) documents the required order: blobs first, action result second.

Source

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

        }
        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() {
                bail!("cannot publish an action result with a missing blob");
            }
        }
        let destination = self.path_for(&result.action)?;
        let replace_invalid = match self.find(&result.action) {
            Ok(Some(existing)) => {
                if existing == *result {
                    return Ok(destination);
                }
                bail!("local action key already has a different result");
            }
            Ok(None) => false,
            Err(_) => true,
        };
        let parent = destination
            .parent()
            .expect("action-result path has a parent");
        fs::create_dir_all(parent)?;
        let mut temporary = tempfile::NamedTempFile::new_in(parent)?;

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Store all referenced blobs first: `cas.store_bytes(&result.action, ...)`, plus metadata and output_root when present, then `actions.store(&result)`.
  2. When publishing downloaded results, materialize blobs into the local CAS before storing the action entry.
  3. As a pre-check, iterate `[result.action, result.metadata, result.output_root]` and confirm `cas.find` returns each.

Example fix

// before
actions.store(&result)?; // bails: referenced blobs missing

// after
cas.store_bytes(&result.action, &manifest_bytes)?;
if let Some(d) = &result.metadata { cas.store_bytes(d, &metadata_bytes)?; }
if let Some(d) = &result.output_root { cas.store_file(d, &output_root_dir)?; }
actions.store(&result)?;
Defensive patterns

Strategy: validation

Validate before calling

let refs = [Some(&result.action), result.metadata.as_ref(), result.output_root.as_ref()]
    .into_iter()
    .flatten();
for digest in refs {
    if cas.find(digest)?.is_none() {
        cas.store_bytes(digest, &materialize(digest).await?)?;
    }
}
actions.store(&result)?;

Prevention

When it happens

Trigger: Calling `actions.store(&result)` before `cas.store_bytes`/`store_file` for the action digest, the metadata digest, or the output-root digest. A common miss is forgetting that the action key blob itself must be present in the CAS, not just the outputs.

Common situations: Publishing only outputs and skipping the action manifest blob; download flows persisting an action result before materializing its blobs into the local CAS.

Related errors


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