jdx/mise · error · eyre::Report
cache agent returned a non-canonical rustc action prediction
Error message
cache agent returned a non-canonical rustc action prediction
What it means
A prediction payload is JSON that must be in canonical form: the wrapper re-serializes the parsed RustcInputPrediction with canonical_json and requires byte-identical output to the payload received. Any difference (key ordering, whitespace, number formatting) means the agent stored or returned non-canonical JSON, so downstream digests could diverge, and the wrapper bails (src/cache/rustc.rs:149).
Source
Thrown at src/cache/rustc.rs:149
invocation: invocation_digest.clone(),
}])?;
let Some(response) = responses.into_iter().next() else {
bail!("cache agent did not return an action prediction response");
};
let prediction = match response {
AgentResponse::ActionPrediction {
prediction: Some(prediction),
} => prediction,
AgentResponse::ActionPrediction { prediction: None } => return Ok(None),
AgentResponse::Error { message } => bail!(message),
_ => bail!("cache agent returned an unexpected action prediction response"),
};
if prediction.adapter != "rustc" || prediction.invocation != invocation_digest {
bail!("cache agent returned an incompatible rustc action prediction");
}
let input_prediction: RustcInputPrediction = serde_json::from_str(&prediction.payload)?;
if String::from_utf8(canonical_json(&input_prediction)?)? != prediction.payload {
bail!("cache agent returned a non-canonical rustc action prediction");
}
let discovered = input_prediction.discover(working_dir, &context.path_mappings)?;
discovered.clone().apply_to(&mut context)?;
let action = invocation.action(context)?;
let restored = restore_result(&action, outputs, &discovered, restore_outputs)?;
if restored.is_some() {
record_prediction_value(invocation_digest, action.digest.clone(), prediction.payload);
}
Ok(restored)
}
fn action_from_dep_info(
rustc: &OsStr,
invocation: &RustcInvocation,
dep_info: &Path,
working_dir: &Path,
) -> Result<(RustcAction, DiscoveredInputs)> {
let dep_info = RustcDepInfo::read(dep_info)?;View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Restart the agent and rebuild with the current mise so payloads are re-recorded canonically
- Delete the agent-side cache blobs so old payloads are regenerated
- Keep agent and wrapper on the same mise build; disable the rustc cache if you must mix versions
Defensive patterns
Strategy: retry
Try / catch
# Canonicalization failures mean stale payloads: reset cache and retry
grep -q 'non-canonical rustc action prediction' build.log && {
rm -rf "$MISE_CACHE_STAGING_DIR"; cargo build;
} Prevention
- Invalidate cache stores on mise version changes
- Keep one mise build (no mixing dev/release) per cache store
- Monitor builds for cache warnings so drift is caught early
When it happens
Trigger: An agent written by (or serialized by) a different mise version whose canonicalization differs — e.g. serde struct field order changed, float formatting changed — making the round-trip comparison fail.
Common situations: Upgrading mise while keeping a long-lived agent/cache; mixing release and development builds against the same cache store.
Related errors
- cache agent returned an unexpected action prediction respons
- cache agent returned an unexpected action lookup response
- cache agent did not return an action prediction response
- cache agent returned an incompatible rustc action prediction
- cache agent returned an unexpected prediction response
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/58cdc3d485b8707e.
Report an issue: GitHub.