jdx/mise · error

remote cache action bytes do not match cache key

Error message

remote cache action bytes do not match cache key

What it means

commit() hashes the serialized action bytes with blake3 and requires the digest to equal the cache key being published. A mismatch means the caller is publishing under a key that does not correspond to the action payload. This guards the remote cache against keys pointing at wrong inputs.

Solutions

  1. Recompute the key as CacheDigest::blake3(action).hash from the exact bytes passed to commit().
  2. Ensure the same action serialization is used for key computation and upload (no intermediate edits).
  3. Begin a fresh write via begin_write(key) with the corrected key instead of reusing a stale write handle.
  4. Verify TASK_CACHE_STORE_VERSION / action format matches between the code computing keys and the code committing.

Example fix

// before
let key = old_key_from_previous_action;
store.commit(&key, &action_bytes, ...).await?;
// after
let key = CacheDigest::blake3(&action_bytes).hash;
store.commit(&key, &action_bytes, ...).await?;
Defensive patterns

Strategy: validation

Validate before calling

let digest = CacheDigest::blake3(&action_bytes);
assert_eq!(digest.hash, key, "key must be blake3(action) before commit");

Type guard

fn key_matches_action(key: &str, action: &[u8]) -> bool {
    CacheDigest::blake3(action).hash == key
}

Try / catch

store.commit(&key, &action, &write, &manifest, has_artifact).await
    .map_err(|e| if e.to_string().contains("do not match cache key") {
        eyre!("key/action mismatch for {key}: recompute key via CacheDigest::blake3(action)")
    } else { e })?;

Prevention

When it happens

Trigger: Calling HttpTaskCacheStore::commit with action bytes whose blake3 digest differs from the key argument (task_cache_store.rs:449), e.g. reusing a TaskCacheStoreWrite from a different action or mutating action bytes after digest computation.

Common situations: Custom cache integrations or tooling that computes the key from a different serialization than the action bytes actually uploaded; refactors that change action encoding while reusing old keys; mixing cache store versions.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/task/task_cache_store.rs:449

        let nonce = crate::rand::random_string(8);
        Ok(TaskCacheStoreWrite {
            artifact_path: self.staging_dir.join(format!("{key}.part-{nonce}.tar.zst")),
            manifest_path: self.staging_dir.join(format!("{key}.part-{nonce}.json")),
        })
    }

    async fn commit(
        &self,
        key: &str,
        action: &[u8],
        write: &TaskCacheStoreWrite,
        manifest: &[u8],
        has_artifact: bool,
    ) -> Result<()> {
        validate_remote_key(key)?;
        let action_digest = CacheDigest::blake3(action);
        if action_digest.hash != key {
            bail!("remote cache action bytes do not match cache key");
        }
        let manifest: CacheManifest = serde_json::from_slice(manifest)?;
        if manifest.key != key {
            bail!("local task cache manifest does not match remote action");
        }
        let metadata = canonical_json(&serde_json::to_value(
            RemoteClientMetadata::from_manifest(&manifest),
        )?)?;
        let mut uploads = vec![
            BlobUpload {
                digest: action_digest.clone(),
                source: BlobSource::Bytes(action.to_vec()),
            },
            BlobUpload {
                digest: CacheDigest::blake3(&metadata),
                source: BlobSource::Bytes(metadata),
            },
        ];

View on GitHub (pinned to 533346cc37)