{"record":{"id":"0f448c046d9481e9","repo":"jdx/mise","slug":"executable-identity-contains-an-unsupported-enviro","errorCode":null,"errorMessage":"executable identity contains an unsupported environment variable","messagePattern":"executable identity contains an unsupported environment variable","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/agent.rs","lineNumber":1676,"sourceCode":"        {\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        }\n        Ok(ExecutableIdentityKey {\n            executable,\n            environment,\n        })\n    }\n\n    fn find_executable_identity(\n        &self,\n        executable: PathBuf,\n        environment: BTreeMap<String, Option<String>>,\n    ) -> Result<AgentResponse> {\n        let key = self.executable_identity_key(executable, environment)?;\n        let stdout = self\n            .executable_identities\n            .lock()\n            .unwrap()\n            .get(&key)","sourceCodeStart":1658,"sourceCodeEnd":1694,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/agent.rs#L1658-L1694","documentation":"executable_identity_key accepts exactly two environment variable names — RUSTUP_HOME and RUSTUP_TOOLCHAIN — because those define a rustc executable's identity. Any other key in the environment map is rejected so identities stay well-defined.","triggerScenarios":"Calling find_executable_identity / store_executable_identity with a map containing anything else: RUSTFLAGS, CARGO_HOME, PATH, LD_LIBRARY_PATH, or an empty-string key.","commonSituations":"Forwarding a whole environment block instead of an allowlist; a newer client wanting extra variables before the deployed agent supports them.","solutions":["Filter the map to {RUSTUP_HOME, RUSTUP_TOOLCHAIN} before calling","If a new variable is genuinely needed, upgrade agent and client together after support is added"],"exampleFix":"// before\nlet env = full_process_env(); // includes RUSTFLAGS, PATH, ...\nagent.store_executable_identity(rustc, env, stdout).await?;\n// after\nlet env: BTreeMap<_,_> = full_process_env()\n    .into_iter()\n    .filter(|(k, _)| matches!(k.as_str(), \"RUSTUP_HOME\" | \"RUSTUP_TOOLCHAIN\"))\n    .collect();\nagent.store_executable_identity(rustc, env, stdout).await?;","handlingStrategy":"validation","validationCode":"fn rustc_identity_env(env: &BTreeMap<String, Option<String>>) -> BTreeMap<String, Option<String>> {\n    env.iter()\n        .filter(|(k, _)| matches!(k.as_str(), \"RUSTUP_HOME\" | \"RUSTUP_TOOLCHAIN\"))\n        .map(|(k, v)| (k.clone(), v.clone()))\n        .collect()\n}","typeGuard":"fn is_supported_identity_env(env: &BTreeMap<String, Option<String>>) -> bool {\n    env.keys().all(|k| matches!(k.as_str(), \"RUSTUP_HOME\" | \"RUSTUP_TOOLCHAIN\"))\n}","tryCatchPattern":null,"preventionTips":["Build identity env maps from an explicit allowlist, never from forwarded process env","Upgrade agent and client in lockstep when new identity variables are introduced"],"tags":["mise-cache","executable-identity","environment","allowlist"],"backgroundTag":"unsupported-env-var","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}