{"record":{"id":"18d1c11a731bf95e","repo":"jdx/mise","slug":"task-action-manifest-contains-too-many-predictions","errorCode":null,"errorMessage":"task action manifest contains too many predictions","messagePattern":"task action manifest contains too many predictions","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/agent.rs","lineNumber":1659,"sourceCode":"            .get(task)\n            .and_then(|state| state.predictions.get(invocation))\n            .cloned();\n        Ok(AgentResponse::ActionPrediction { prediction })\n    }\n\n    fn record_action_prediction(\n        &self,\n        task: &str,\n        prediction: ActionPrediction,\n    ) -> Result<AgentResponse> {\n        validate_task_identity(task)?;\n        validate_action_prediction(&prediction)?;\n        let mut tasks = self.task_actions.lock().unwrap();\n        let state = tasks.entry(task.to_string()).or_default();\n        if !state.predictions.contains_key(&prediction.invocation)\n            && state.predictions.len() >= MAX_TASK_ACTION_PREDICTIONS\n        {\n            bail!(\"task action manifest contains too many predictions\");\n        }\n        state\n            .predictions\n            .insert(prediction.invocation.clone(), prediction);\n        Ok(AgentResponse::ActionPredictionRecorded)\n    }\n\n    fn executable_identity_key(\n        &self,\n        executable: PathBuf,\n        environment: BTreeMap<String, Option<String>>,\n    ) -> Result<ExecutableIdentityKey> {\n        if !environment\n            .keys()\n            .all(|name| matches!(name.as_str(), \"RUSTUP_HOME\" | \"RUSTUP_TOOLCHAIN\"))\n        {\n            bail!(\"executable identity contains an unsupported environment variable\");\n        }","sourceCodeStart":1641,"sourceCodeEnd":1677,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/agent.rs#L1641-L1677","documentation":"record_action_prediction caps distinct invocation keys per task at MAX_TASK_ACTION_PREDICTIONS (16,384). The cap is enforced only for NEW keys — updating an already-recorded invocation never trips it.","triggerScenarios":"A task run records more than 16,384 distinct prediction.invocation digests, typically because each run produces unique digests (timestamps, absolute temp paths, random values baked into the invocation).","commonSituations":"Non-hermetic actions whose invocation digest changes every run (nondeterministic env, random temp dirs); fuzzing or generated-code workloads creating unbounded distinct invocations.","solutions":["Make invocations deterministic so digest keys repeat across runs (stable env, relative paths, no timestamps)","Split the workload across multiple task identities so each stays under the cap","Stop recording predictions for actions that will never repeat — they only consume the per-task budget"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const MAX_PREDICTIONS: usize = 16 * 1024;\nlet mut recorded: HashSet<InvocationDigest> = HashSet::new();\nfn should_record(recorded: &HashSet<InvocationDigest>, inv: &InvocationDigest) -> bool {\n    recorded.contains(inv) || recorded.len() < MAX_PREDICTIONS\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep invocations hermetic: no timestamps, absolute temp paths, or random values in inputs","Skip recording predictions for one-shot actions that will never repeat","Watch prediction growth per task — steady growth toward 16k signals non-determinism"],"tags":["mise-cache","task-manifest","resource-limit","determinism"],"backgroundTag":"cache-entry-too-large","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}