{"record":{"id":"d1283fd4b4a3c28e","repo":"jdx/mise","slug":"remote-cache-action-bytes-do-not-match-cache-key","errorCode":null,"errorMessage":"remote cache action bytes do not match cache key","messagePattern":"remote cache action bytes do not match cache key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/task/task_cache_store.rs","lineNumber":449,"sourceCode":"        let nonce = crate::rand::random_string(8);\n        Ok(TaskCacheStoreWrite {\n            artifact_path: self.staging_dir.join(format!(\"{key}.part-{nonce}.tar.zst\")),\n            manifest_path: self.staging_dir.join(format!(\"{key}.part-{nonce}.json\")),\n        })\n    }\n\n    async fn commit(\n        &self,\n        key: &str,\n        action: &[u8],\n        write: &TaskCacheStoreWrite,\n        manifest: &[u8],\n        has_artifact: bool,\n    ) -> Result<()> {\n        validate_remote_key(key)?;\n        let action_digest = CacheDigest::blake3(action);\n        if action_digest.hash != key {\n            bail!(\"remote cache action bytes do not match cache key\");\n        }\n        let manifest: CacheManifest = serde_json::from_slice(manifest)?;\n        if manifest.key != key {\n            bail!(\"local task cache manifest does not match remote action\");\n        }\n        let metadata = canonical_json(&serde_json::to_value(\n            RemoteClientMetadata::from_manifest(&manifest),\n        )?)?;\n        let mut uploads = vec![\n            BlobUpload {\n                digest: action_digest.clone(),\n                source: BlobSource::Bytes(action.to_vec()),\n            },\n            BlobUpload {\n                digest: CacheDigest::blake3(&metadata),\n                source: BlobSource::Bytes(metadata),\n            },\n        ];","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/task/task_cache_store.rs#L431-L467","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Recompute the key as CacheDigest::blake3(action).hash from the exact bytes passed to commit().","Ensure the same action serialization is used for key computation and upload (no intermediate edits).","Begin a fresh write via begin_write(key) with the corrected key instead of reusing a stale write handle.","Verify TASK_CACHE_STORE_VERSION / action format matches between the code computing keys and the code committing."],"exampleFix":"// before\nlet key = old_key_from_previous_action;\nstore.commit(&key, &action_bytes, ...).await?;\n// after\nlet key = CacheDigest::blake3(&action_bytes).hash;\nstore.commit(&key, &action_bytes, ...).await?;","handlingStrategy":"validation","validationCode":"let digest = CacheDigest::blake3(&action_bytes);\nassert_eq!(digest.hash, key, \"key must be blake3(action) before commit\");","typeGuard":"fn key_matches_action(key: &str, action: &[u8]) -> bool {\n    CacheDigest::blake3(action).hash == key\n}","tryCatchPattern":"store.commit(&key, &action, &write, &manifest, has_artifact).await\n    .map_err(|e| if e.to_string().contains(\"do not match cache key\") {\n        eyre!(\"key/action mismatch for {key}: recompute key via CacheDigest::blake3(action)\")\n    } else { e })?;","preventionTips":["Always derive the key from the exact bytes uploaded, never from a cached or precomputed value.","Freeze action bytes before computing the key; no edits afterwards.","Write unit tests asserting key == blake3(action) for your publish path.","Avoid reusing TaskCacheStoreWrite handles across actions."],"tags":["cache","checksum","integrity","remote"],"backgroundTag":"checksum-mismatch","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}