{"record":{"id":"899ad18ba7311469","repo":"zeroclaw-labs/zeroclaw","slug":"grok-cli-env-passthrough-entry-name-is-provide","errorCode":null,"errorMessage":"grok_cli env_passthrough entry `{name}` is provider-owned (`XAI_*` other than `XAI_API_KEY`, and all `GROK_*`); other names (for example tool credentials) may be listed explicitly, and Grok CLI policy flags belong in `extra_args`","messagePattern":"grok_cli env_passthrough entry `(.+?)` is provider-owned \\(`XAI_\\*` other than `XAI_API_KEY`, and all `GROK_\\*`\\); other names \\(for example tool credentials\\) may be listed explicitly, and Grok CLI policy flags belong in `extra_args`","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/grok_cli.rs","lineNumber":526,"sourceCode":"                \"grok_cli max_acp_stdout_bytes must be between {} and {} bytes\",\n                acp::MIN_ACP_STDOUT_LIMIT_BYTES,\n                acp::MAX_ACP_STDOUT_LIMIT_BYTES\n            );\n        }\n        Ok(limit)\n    }\n\n    fn normalize_and_validate_env_passthrough(names: Vec<String>) -> anyhow::Result<Vec<String>> {\n        let mut normalized: Vec<String> = Vec::with_capacity(names.len());\n        for name in names {\n            let name = name.trim();\n            if !is_valid_env_var_name(name) {\n                anyhow::bail!(\n                    \"grok_cli env_passthrough entry `{name}` is invalid; expected [A-Za-z_][A-Za-z0-9_]*\"\n                );\n            }\n            if is_disallowed_provider_env_var(name) {\n                anyhow::bail!(\n                    \"grok_cli env_passthrough entry `{name}` is provider-owned \\\n                     (`XAI_*` other than `XAI_API_KEY`, and all `GROK_*`); \\\n                     other names (for example tool credentials) may be listed \\\n                     explicitly, and Grok CLI policy flags belong in `extra_args`\"\n                );\n            }\n            if !normalized\n                .iter()\n                .any(|existing| env_names_equal(existing.as_str(), name))\n            {\n                // Preserve the operator-supplied spelling; equality is\n                // case-insensitive on Windows when checking membership later.\n                normalized.push(name.to_string());\n            }\n        }\n        Ok(normalized)\n    }\n","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/grok_cli.rs#L508-L544","documentation":"env_passthrough blocks provider-owned names: every GROK_* variable and all XAI_* except XAI_API_KEY, because ZeroClaw injects those itself and a passthrough entry would fight the provider. Other names (e.g. tool credentials) are explicitly allowed; Grok CLI policy flags belong in extra_args, not env.","triggerScenarios":"Listing XAI_API_TIMEOUT, XAI_BASE_URL, or GROK_MODEL in env_passthrough; migrating a manual grok CLI invocation that exported GROK_* vars and keeping them in the passthrough list.","commonSituations":"Ported shell wrappers; attempts to override model or policy through environment instead of config; security reviews tightening env hygiene.","solutions":["Remove the provider-owned entry; configure the equivalent behavior through provider fields or extra_args","Keep XAI_API_KEY in env_passthrough only if the key must come from the environment","For tool credentials (non-provider names), leave them listed - they are allowed"],"exampleFix":"# before\nenv_passthrough = [\"XAI_API_KEY\", \"GROK_MODEL\", \"PATH\"]\n\n# after\nenv_passthrough = [\"XAI_API_KEY\", \"PATH\"]  # model goes in the model field / extra_args","handlingStrategy":"validation","validationCode":"fn is_provider_owned_env(name: &str) -> bool {\n    let n = name.to_ascii_uppercase();\n    n.starts_with(\"GROK_\") || (n.starts_with(\"XAI_\") && n != \"XAI_API_KEY\")\n}\n\nfn passthrough_entry_allowed(name: &str) -> bool {\n    valid_env_var_name(name) && !is_provider_owned_env(name)\n}","typeGuard":"fn is_provider_owned_env(name: &str) -> bool {\n    let n = name.to_ascii_uppercase();\n    n.starts_with(\"GROK_\") || (n.starts_with(\"XAI_\") && n != \"XAI_API_KEY\")\n}","tryCatchPattern":null,"preventionTips":["Keep provider policy in extra_args and provider fields, never env","When porting shell wrappers, strip all GROK_*/XAI_* exports except XAI_API_KEY","Re-run config lint after grok_cli version upgrades that add provider vars"],"tags":["rust","zeroclaw","grok-cli","environment-variables","reserved-names","configuration"],"backgroundTag":"reserved-config-key","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}