jdx/mise · error
task action manifest contains duplicate predictions
Error message
task action manifest contains duplicate predictions
What it means
Thrown by validate_task_manifest (crates/mise-cache-core/src/agent.rs:1831) when two predictions in the same manifest share an identical invocation value. The validator inserts each prediction.invocation into a BTreeMap and bails if the key was already present, because the cache resolves predictions by invocation — a duplicate would make the lookup ambiguous.
Source
Thrown at crates/mise-cache-core/src/agent.rs:1831
if prediction.payload.len() > MAX_ACTION_PREDICTION_PAYLOAD {
bail!("action prediction payload is too large");
}
serde_json::from_str::<serde_json::Value>(&prediction.payload)?;
Ok(())
}
fn validate_task_manifest(manifest: &TaskActionManifest, task: &str) -> Result<()> {
if manifest.version != TASK_ACTION_MANIFEST_VERSION || manifest.task != task {
bail!("task action manifest has an invalid identity");
}
if manifest.predictions.len() > MAX_TASK_ACTION_PREDICTIONS {
bail!("task action manifest contains too many predictions");
}
let mut invocations = BTreeMap::new();
for prediction in &manifest.predictions {
validate_action_prediction(prediction)?;
if invocations.insert(&prediction.invocation, ()).is_some() {
bail!("task action manifest contains duplicate predictions");
}
}
Ok(())
}
fn merge_task_manifests(
task: &str,
base: Option<TaskActionManifest>,
update: TaskActionManifest,
) -> Result<TaskActionManifest> {
validate_task_manifest(&update, task)?;
let mut predictions = BTreeMap::new();
if let Some(base) = base {
validate_task_manifest(&base, task)?;
predictions.extend(
base.predictions
.into_iter()
.map(|prediction| (prediction.invocation.clone(), prediction)),View on GitHub (pinned to 6f52dcdf99)
Solutions
- Deduplicate the predictions array by invocation before persisting/merging (keep the newest payload per invocation)
- Fix the producer so it never emits two predictions for one invocation — treat an existing invocation as an update, not an append
- Inspect the duplicate invocations: if many are empty strings, the invocation extraction upstream is broken; fix that instead of deduping the symptom
- Regenerate the manifest after the fix so the stored file no longer contains duplicates
Example fix
// before let mut predictions = old_manifest.predictions; predictions.extend(new_manifest.predictions); // may duplicate invocations // after let mut by_invocation: BTreeMap<String, ActionPrediction> = old_manifest.predictions.into_iter().map(|p| (p.invocation.clone(), p)).collect(); by_invocation.extend(new_manifest.predictions.into_iter().map(|p| (p.invocation.clone(), p))); let predictions = by_invocation.into_values().collect();
Defensive patterns
Strategy: validation
Validate before calling
use std::collections::BTreeMap;
fn dedupe_predictions(predictions: Vec<ActionPrediction>) -> Vec<ActionPrediction> {
predictions
.into_iter()
.map(|p| (p.invocation.clone(), p))
.collect::<BTreeMap<_, _>>()
.into_values()
.collect()
}
// run before persisting/merging Type guard
fn has_unique_invocations(m: &TaskActionManifest) -> bool {
let mut seen = std::collections::BTreeSet::new();
m.predictions.iter().all(|p| seen.insert(p.invocation.clone()))
} Try / catch
match merge_task_manifests(task, base, update) {
Err(e) if e.to_string().contains("duplicate predictions") => {
let deduped = dedupe_predictions(update.predictions);
merge_task_manifests(task, base, TaskActionManifest { predictions: deduped, ..update })
}
other => other,
} Prevention
- Key predictions by invocation in your producer (map, not list) so duplicates are structurally impossible
- When merging two manifests, upsert by invocation instead of concatenating
- Fail loudly in the producer if an invocation repeats — it usually signals a broken extraction step
When it happens
Trigger: Passing a manifest to merge_task_manifests (agent.rs:1836) where predictions[i].invocation == predictions[j].invocation for some i != j. Happens when a producer appends predictions for the same command line twice (e.g. merging overlapping runs without keyed dedup, or generating one entry per source file where several produce the identical invocation string).
Common situations: Manual manifest construction or a generator loop that emits a default/empty invocation for entries it could not classify; merging two manifests that both contain a common invocation before deduplicating; unstable serialization that collapses distinct invocations to the same string.
Related errors
- action prediction payload is too large
- task action manifest has an invalid identity
- unsupported remote cache digest algorithm
- invalid remote cache digest
- remote cache action keys must use blake3
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/78582c35431c87b3.
Report an issue: GitHub.