{"record":{"id":"10c362377247c8c2","repo":"jdx/mise","slug":"remote-cache-directory-contains-duplicate-names","errorCode":null,"errorMessage":"remote cache directory contains duplicate names","messagePattern":"remote cache directory contains duplicate names","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/task/task_cache_store.rs","lineNumber":729,"sourceCode":"    let mut pending = vec![(PathBuf::new(), root.clone(), BTreeSet::new())];\n    let mut nodes = BTreeMap::<PathBuf, RestoredNode>::new();\n    while let Some((path, digest, mut ancestors)) = pending.pop() {\n        if !ancestors.insert(digest.clone()) {\n            bail!(\"remote cache directory graph contains a cycle\");\n        }\n        let bytes = store.client.get_blob(&digest, DIRECTORY_MEDIA_TYPE).await?;\n        let directory: RemoteDirectory = serde_json::from_slice(&bytes)?;\n        if canonical_json(&serde_json::to_value(&directory)?)? != bytes {\n            bail!(\"remote cache directory is not canonical JSON\");\n        }\n        if directory.version != 1 {\n            bail!(\"unsupported remote cache directory version\");\n        }\n        let mut names = BTreeSet::new();\n        for directory in directory.directories {\n            validate_cache_name(&directory.name)?;\n            if !names.insert(directory.name.clone()) {\n                bail!(\"remote cache directory contains duplicate names\");\n            }\n            let child = path.join(&directory.name);\n            validate_cache_path(&child)?;\n            nodes.insert(\n                child.clone(),\n                RestoredNode::Directory {\n                    mode: directory.mode,\n                },\n            );\n            pending.push((child, directory.digest, ancestors.clone()));\n        }\n        for file in directory.files {\n            validate_cache_name(&file.name)?;\n            if !names.insert(file.name.clone()) {\n                bail!(\"remote cache directory contains duplicate names\");\n            }\n            let child = path.join(&file.name);\n            validate_cache_path(&child)?;","sourceCodeStart":711,"sourceCodeEnd":747,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/task/task_cache_store.rs#L711-L747","documentation":"Within a remote directory blob, all child entry names (across directories, files, and symlinks) must be unique. When walking the `directories` list, inserting a name that is already in the names set bails, because a filesystem cannot contain two entries with the same name.","triggerScenarios":"A remote directory blob lists two subdirectory entries with the same `name` value in its `directories` array.","commonSituations":"Blobs produced by a buggy or malicious cache writer that doesn't deduplicate entries; hand-edited JSON; corrupted remote data after a bad merge of directory listings.","solutions":["Delete the offending directory blob from the remote store and re-run the task to regenerate it.","Fix the producer to deduplicate entries by name before serializing the directory blob.","Validate cached blobs with a script that checks for duplicate names across directories/files/symlinks.","Avoid hand-editing remote cache blobs."],"exampleFix":"// before: duplicate subdirectory names\n{\"version\":1,\"directories\":[{\"name\":\"a\",...},{\"name\":\"a\",...}],...}\n// after: unique names\n{\"version\":1,\"directories\":[{\"name\":\"a\",...}],...}","handlingStrategy":"validation","validationCode":"const names = blob.directories.map(d => d.name);\nif (new Set(names).size !== names.length) throw new Error('duplicate directory names');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deduplicate entries by name before serializing directory blobs.","Never hand-edit remote cache JSON.","Lint blobs for duplicate names before upload."],"tags":["task-cache","remote-cache","duplicate-names","validation"],"backgroundTag":"internal-invariant-violation","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"}