jdx/mise · error
remote cache directory is not canonical JSON
Error message
remote cache directory is not canonical JSON
What it means
Remote directory blobs are required to be stored as canonical JSON (keys sorted, no insignificant whitespace). After deserializing and re-serializing the blob, mise compares the canonical form to the raw bytes; a mismatch means the blob was written by a non-conforming producer, so it bails rather than trusting it.
Solutions
- Re-upload the cache entries using mise itself (re-run the task) so blobs are written with canonical JSON.
- Fix the custom cache producer to serialize with mise's canonical JSON routine (sorted keys, compact output).
- Purge affected blobs from the remote store and let clients repopulate them.
- Check whether any storage layer is re-encoding JSON on write/read and disable that transformation.
Example fix
// before: pretty, non-canonical serde_json::to_string_pretty(&directory) // after: canonical form as required serde_json::to_vec(&directory)
Defensive patterns
Strategy: validation
Validate before calling
const canonical = o => JSON.stringify(o, Object.keys(o).sort());
if (canonical(parsed) !== rawString) throw new Error('directory blob is not canonical JSON'); Prevention
- Serialize directory blobs with sorted keys and compact output only.
- Disable any intermediary (proxy/storage layer) that re-serializes JSON.
- Write blobs via mise itself rather than custom serializers.
When it happens
Trigger: get_blob returns a directory blob whose bytes differ from canonical_json(serde_json::to_value(directory)) — i.e. the blob was serialized with unsorted keys, extra whitespace, or other non-canonical formatting.
Common situations: A custom or older cache writer stored pretty-printed or non-deterministically ordered JSON; blobs were transformed/normalized by an intermediary (proxy, CDN) that re-serialized them; manual editing of remote blobs.
Related errors
- invalid remote task cache key
- remote cache client metadata is not canonical JSON
- remote cache directory contains duplicate names
- remote cache directory graph contains a cycle
- task action manifest is not canonical JSON
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/a0d8529dab591cca.
Report an issue: GitHub.
Appendix: source
Thrown at src/task/task_cache_store.rs:720
mode: u32,
target: PathBuf,
},
}
async fn materialize_remote_tree(
store: &HttpTaskCacheStore,
root: &CacheDigest,
) -> Result<tempfile::NamedTempFile> {
let mut pending = vec![(PathBuf::new(), root.clone(), BTreeSet::new())];
let mut nodes = BTreeMap::<PathBuf, RestoredNode>::new();
while let Some((path, digest, mut ancestors)) = pending.pop() {
if !ancestors.insert(digest.clone()) {
bail!("remote cache directory graph contains a cycle");
}
let bytes = store.client.get_blob(&digest, DIRECTORY_MEDIA_TYPE).await?;
let directory: RemoteDirectory = serde_json::from_slice(&bytes)?;
if canonical_json(&serde_json::to_value(&directory)?)? != bytes {
bail!("remote cache directory is not canonical JSON");
}
if directory.version != 1 {
bail!("unsupported remote cache directory version");
}
let mut names = BTreeSet::new();
for directory in directory.directories {
validate_cache_name(&directory.name)?;
if !names.insert(directory.name.clone()) {
bail!("remote cache directory contains duplicate names");
}
let child = path.join(&directory.name);
validate_cache_path(&child)?;
nodes.insert(
child.clone(),
RestoredNode::Directory {
mode: directory.mode,
},
);View on GitHub (pinned to 533346cc37)