{"record":{"id":"e57a04fa1a9e5e7c","repo":"jdx/mise","slug":"action-prediction-payload-is-too-large","errorCode":null,"errorMessage":"action prediction payload is too large","messagePattern":"action prediction payload is too large","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/agent.rs","lineNumber":1814,"sourceCode":"    {\n        bail!(\"invalid task action identity\");\n    }\n    Ok(())\n}\n\nfn validate_action_prediction(prediction: &ActionPrediction) -> Result<()> {\n    prediction.invocation.validate()?;\n    prediction.action.validate()?;\n    if prediction.adapter.is_empty()\n        || !prediction\n            .adapter\n            .bytes()\n            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))\n    {\n        bail!(\"invalid action prediction adapter\");\n    }\n    if prediction.payload.len() > MAX_ACTION_PREDICTION_PAYLOAD {\n        bail!(\"action prediction payload is too large\");\n    }\n    serde_json::from_str::<serde_json::Value>(&prediction.payload)?;\n    Ok(())\n}\n\nfn validate_task_manifest(manifest: &TaskActionManifest, task: &str) -> Result<()> {\n    if manifest.version != TASK_ACTION_MANIFEST_VERSION || manifest.task != task {\n        bail!(\"task action manifest has an invalid identity\");\n    }\n    if manifest.predictions.len() > MAX_TASK_ACTION_PREDICTIONS {\n        bail!(\"task action manifest contains too many predictions\");\n    }\n    let mut invocations = BTreeMap::new();\n    for prediction in &manifest.predictions {\n        validate_action_prediction(prediction)?;\n        if invocations.insert(&prediction.invocation, ()).is_some() {\n            bail!(\"task action manifest contains duplicate predictions\");\n        }","sourceCodeStart":1796,"sourceCodeEnd":1832,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/agent.rs#L1796-L1832","documentation":"Thrown by validate_action_prediction in the task-action-manifest pipeline (crates/mise-cache-core/src/agent.rs:1814) when a prediction's payload string exceeds MAX_ACTION_PREDICTION_PAYLOAD (256 KiB, defined at agent.rs:23). Each ActionPrediction carries its prediction as a JSON string; the size cap bounds memory/CPU when manifests are merged or persisted. The check runs before the payload is parsed with serde_json, so oversized payloads are rejected without any JSON work.","triggerScenarios":"Calling any API that persists or merges task action manifests (e.g. merge_task_manifests at agent.rs:1836, which calls validate_task_manifest -> validate_action_prediction) with a manifest whose predictions[i].payload.len() > 262144. Also hit when an external producer of the manifest file writes a large inline payload blob.","commonSituations":"A task embeds base64-encoded file contents, full environment dumps, or a whole tool output snapshot into prediction.payload instead of referencing blobs by digest; manifests generated by a newer/different tool without the size cap; hand-edited manifest files in the cache directory.","solutions":["Shrink the prediction payload to under 256 KiB: store large content as a cache blob (CacheDigest reference) and keep only a pointer/metadata in payload","Check what the payload actually contains — if it duplicates file contents, replace it with the digest of the uploaded blob","If you control the manifest producer, gzip/compact the JSON or split one huge prediction into several smaller ones (still under the per-prediction cap)","If a genuinely larger cap is required, raise MAX_ACTION_PREDICTION_PAYLOAD in a fork and rebuild — there is no runtime knob"],"exampleFix":"// before\nlet prediction = ActionPrediction {\n    invocation,\n    action,\n    adapter: \"cargo\".into(),\n    payload: serde_json::to_string(&entire_tool_output)?, // may exceed 256 KiB\n};\n\n// after\nlet digest = cache.put_blob_bytes(&entire_tool_output_bytes).await?; // store as blob\nlet prediction = ActionPrediction {\n    invocation,\n    action,\n    adapter: \"cargo\".into(),\n    payload: serde_json::to_string(&serde_json::json!({ \"blob\": digest }))?,\n};","handlingStrategy":"validation","validationCode":"const MAX_ACTION_PREDICTION_PAYLOAD: usize = 256 * 1024;\n\nfn check_payload_size(prediction: &ActionPrediction) -> Result<(), String> {\n    if prediction.payload.len() > MAX_ACTION_PREDICTION_PAYLOAD {\n        Err(format!(\"payload is {} bytes, cap is {}\", prediction.payload.len(), MAX_ACTION_PREDICTION_PAYLOAD))\n    } else {\n        Ok(())\n    }\n}\n// run before persist/merge:\nfor p in &manifest.predictions { check_payload_size(p)?; }","typeGuard":"fn is_payload_within_cap(p: &ActionPrediction) -> bool {\n    p.payload.len() <= 256 * 1024\n}","tryCatchPattern":"match merge_task_manifests(task, base, update) {\n    Err(e) if e.to_string().contains(\"payload is too large\") => {\n        // move oversized content to a blob and rebuild the prediction\n        rebuild_prediction_with_blob_reference(update)?;\n    }\n    other => other?,\n}","preventionTips":["Never inline file contents or tool output into prediction.payload; store blobs by digest and reference them","Enforce the 256 KiB cap at the producer with a unit test so oversized payloads fail in CI, not in the cache layer","Log payload sizes when generating manifests to catch growth early"],"tags":["mise","cache","validation","payload-size","task-manifest"],"backgroundTag":"payload-too-large","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}