zeroclaw-labs/zeroclaw · error · anyhow::Error
grok_cli env_passthrough entry `{name}` is invalid; expected
Error message
grok_cli env_passthrough entry `{name}` is invalid; expected [A-Za-z_][A-Za-z0-9_]* What it means
Every env_passthrough entry must match [A-Za-z_][A-Za-z0-9_]* after trimming; normalize_and_validate_env_passthrough rejects malformed names before the child environment is assembled, preventing garbled or injected env assignments.
Source
Thrown at crates/zeroclaw-providers/src/grok_cli.rs:521
fn validate_acp_stdout_limit(value: Option<usize>) -> anyhow::Result<usize> {
let limit = value.unwrap_or(acp::DEFAULT_ACP_STDOUT_LIMIT_BYTES);
if !(acp::MIN_ACP_STDOUT_LIMIT_BYTES..=acp::MAX_ACP_STDOUT_LIMIT_BYTES).contains(&limit) {
anyhow::bail!(
"grok_cli max_acp_stdout_bytes must be between {} and {} bytes",
acp::MIN_ACP_STDOUT_LIMIT_BYTES,
acp::MAX_ACP_STDOUT_LIMIT_BYTES
);
}
Ok(limit)
}
fn normalize_and_validate_env_passthrough(names: Vec<String>) -> anyhow::Result<Vec<String>> {
let mut normalized: Vec<String> = Vec::with_capacity(names.len());
for name in names {
let name = name.trim();
if !is_valid_env_var_name(name) {
anyhow::bail!(
"grok_cli env_passthrough entry `{name}` is invalid; expected [A-Za-z_][A-Za-z0-9_]*"
);
}
if is_disallowed_provider_env_var(name) {
anyhow::bail!(
"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`"
);
}
if !normalized
.iter()
.any(|existing| env_names_equal(existing.as_str(), name))
{
// Preserve the operator-supplied spelling; equality is
// case-insensitive on Windows when checking membership later.
normalized.push(name.to_string());View on GitHub (pinned to 88bb9c8533)
Solutions
- Fix the entry to identifier form (letters, digits, underscore, not starting with a digit)
- Drop empty entries; entries are trimmed, so remove stray whitespace-only items
- If you meant a value assignment, use the CLI's own flag mechanism instead
Example fix
# before env_passthrough = ["FOO-BAR", "1BAZ", ""] # after env_passthrough = ["FOO_BAR", "BAZ"]
Defensive patterns
Strategy: validation
Validate before calling
fn valid_env_var_name(name: &str) -> bool {
let mut chars = name.chars();
matches!(chars.next(), Some(c) if c.is_ascii_alphabetic() || c == '_')
&& chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
} Type guard
fn valid_env_var_name(name: &str) -> bool {
let mut chars = name.chars();
matches!(chars.next(), Some(c) if c.is_ascii_alphabetic() || c == '_')
&& chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
} Prevention
- Lint env_passthrough lists in config CI
- Paste names only, never KEY=VALUE pairs
- Trim before validation since entries are trimmed by the provider
When it happens
Trigger: Entries like 'FOO BAR', '1FOO', 'FOO-BAR', values containing '=', or entries that are empty after trim; Windows-style '%VAR%' names pasted from cmd docs.
Common situations: YAML/TOML lists pasted with quotes or trailing spaces; names copied from a shell export line including the value; locale-specific characters in names.
Related errors
- risk_profiles.{profile_alias}.shell_env_passthrough[{i}] is
- grok_cli env_passthrough entry `{name}` is provider-owned (`
- grok_cli extra_args accepts long flags only and must not inc
- cloud_ops.iac_tools must not be empty when cloud_ops is enab
- gateway.path_prefix contains invalid character '{bad}'; only
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/82050987d6e0bc98.
Report an issue: GitHub.