jdx/mise · error
remote action result is missing its output root
Error message
remote action result is missing its output root
What it means
A downloaded remote action result must include an output-root tree when its manifest lists roots (files to restore). If output_root is absent while roots is non-empty, the entry is internally inconsistent — metadata promises artifacts that were never uploaded — and mise refuses to fabricate them.
Source
Thrown at src/task/task_cache_store.rs:418
let metadata_bytes = self
.client
.get_blob(metadata, CLIENT_METADATA_MEDIA_TYPE)
.await?;
let metadata: RemoteClientMetadata = serde_json::from_slice(&metadata_bytes)?;
if canonical_json(&serde_json::to_value(&metadata)?)? != metadata_bytes {
bail!("remote cache client metadata is not canonical JSON");
}
let mut manifest = metadata.into_manifest(key)?;
for root in &manifest.roots {
validate_cache_path(root)?;
}
let artifact = match &result.output_root {
Some(root) => {
let temporary = materialize_remote_tree(self, root).await?;
Some(TaskCacheStoreArtifact::temporary(temporary))
}
None if manifest.roots.is_empty() => None,
None => bail!("remote action result is missing its output root"),
};
manifest.artifact_checksum = Some(calculate_artifact_checksum(
&manifest,
artifact.as_ref().map(TaskCacheStoreArtifact::path),
)?);
let manifest = serde_json::to_vec(&manifest)?;
Ok(Some(TaskCacheStoreEntry { manifest, artifact }))
}
fn begin_write(&self, key: &str) -> Result<TaskCacheStoreWrite> {
validate_remote_key(key)?;
file::create_dir_all(&self.staging_dir)?;
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")),
})
}View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Purge the offending remote key (or its prefix) so the task re-runs and writes a complete entry
- If it recurs, look for interrupted uploads: CI timeouts, proxy body-size limits, flaky networks
- Report upstream if entries are consistently half-written on a current pinned mise
Example fix
# before: half-uploaded entry keeps failing restore # after: evict and re-run aws s3 rm --recursive s3://cache/tasks/<key-prefix> mise run build
Defensive patterns
Strategy: fallback
Try / catch
// a half-written remote entry is a miss; evict and rebuild
match fetch_remote_entry(&key).await {
Ok(e) => Some(e),
Err(err) if err.to_string().contains("remote action result is missing its output root") => {
evict_remote(&key).await;
None
}
Err(err) => return Err(err),
} Prevention
- Let CI cancel gracefully instead of killing uploads mid-flight
- Alert on repeated half-written entries — it signals upload flakiness
- Check lifecycle rules are not deleting artifact blobs independently of metadata
When it happens
Trigger: get() matches result.output_root = None with a manifest whose roots are non-empty — typically a commit interrupted after metadata upload but before the artifact tree, leaving a half-written entry.
Common situations: Upload killed mid-transaction (network drop, CI cancel, timeout); a writer bug in an experimental build; lifecycle rules deleting blobs but not metadata.
Related errors
- remote cache directory graph contains a cycle
- remote cache directory is not canonical JSON
- remote cache directory contains duplicate names
- unsupported remote cache client metadata version
- remote cache metadata kind is not a task
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/1c22b18ce9ba745a.
Report an issue: GitHub.