{"record":{"id":"0446220c2368c184","repo":"jdx/mise","slug":"executable-identity-cache-contains-too-many-bytes","errorCode":null,"errorMessage":"executable identity cache contains too many bytes","messagePattern":"executable identity cache contains too many bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/agent.rs","lineNumber":1717,"sourceCode":"    fn store_executable_identity(\n        &self,\n        executable: PathBuf,\n        environment: BTreeMap<String, Option<String>>,\n        stdout: Vec<u8>,\n    ) -> Result<AgentResponse> {\n        if stdout.len() > MAX_EXECUTABLE_IDENTITY_SIZE {\n            bail!(\"executable identity exceeds {MAX_EXECUTABLE_IDENTITY_SIZE} bytes\");\n        }\n        let key = self.executable_identity_key(executable, environment)?;\n        let mut identities = self.executable_identities.lock().unwrap();\n        let is_new = !identities.contains_key(&key);\n        let previous_size = identities.get(&key).map_or(0, Vec::len);\n        if is_new && identities.len() >= MAX_EXECUTABLE_IDENTITIES {\n            bail!(\"executable identity cache contains too many entries\");\n        }\n        let retained_bytes = identities.values().map(Vec::len).sum::<usize>();\n        if retained_bytes - previous_size + stdout.len() > MAX_EXECUTABLE_IDENTITY_BYTES {\n            bail!(\"executable identity cache contains too many bytes\");\n        }\n        identities.insert(key, stdout.clone());\n        Ok(AgentResponse::ExecutableIdentity {\n            stdout: Some(stdout),\n        })\n    }\n\n    /// Serve newline-delimited protocol requests on an authenticated session stream.\n    pub async fn handle_connection<S>(&self, stream: S) -> Result<()>\n    where\n        S: AsyncRead + AsyncWrite + Unpin,\n    {\n        let (reader, mut writer) = tokio::io::split(stream);\n        let mut lines = BufReader::new(reader).lines();\n        let hello = lines\n            .next_line()\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"connection closed before the agent handshake\"))?;","sourceCodeStart":1699,"sourceCodeEnd":1735,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/agent.rs#L1699-L1735","documentation":"store_executable_identity enforces a total byte budget of MAX_EXECUTABLE_IDENTITY_BYTES (262,144 bytes) across all cached identity blobs: retained_bytes - previous_size + stdout.len() must stay within budget. Many small or a few large identities can both exhaust it.","triggerScenarios":"Storing a new identity when existing blobs already occupy close to 256KiB; or one blob near the 64KiB per-entry limit pushing the total over budget.","commonSituations":"Sessions probing many toolchains with verbose identity output; long-lived agents accumulating identities without restart.","solutions":["Trim identity stdout to the minimal version line before storing","Probe fewer distinct executables per session","Restart the agent/session — the identity cache is in-memory and resets"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const MAX_IDENTITY_BYTES: usize = 256 * 1024;\nlet mut retained: usize = 0;\nfn fits_budget(retained: usize, stdout_len: usize) -> bool {\n    retained + stdout_len <= MAX_IDENTITY_BYTES\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Store the minimal identity string (one version line), not full verbose dumps","Bound distinct executables probed per session — both entry-count and byte budgets apply","Restart long-lived sessions to reset the in-memory identity cache"],"tags":["mise-cache","executable-identity","memory-budget","cache-limit"],"backgroundTag":"cache-capacity-exceeded","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}