zeroclaw-labs/zeroclaw · error

risk_profiles.{profile_alias}.shell_env_passthrough[{i}] is

Error message

risk_profiles.{profile_alias}.shell_env_passthrough[{i}] is invalid ({env_name}); expected [A-Za-z_][A-Za-z0-9_]*

What it means

Every entry under [risk_profiles.<alias>] shell_env_passthrough must be a bare environment variable name matching [A-Za-z_][A-Za-z0-9_]* (is_valid_env_var_name, schema.rs:12422). Profiles are checked in sorted alias order and the message includes the failing index, so the exact entry is identifiable. Values carrying assignments, hyphens, dots, leading digits, or emptiness cannot be matched against a real process environment and are rejected.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:21366

                                "mcp_bundle": bundle_alias,
                            })),
                            "agents.<alias>.mcp_bundles references an undefined [mcp_bundles.<alias>]; the agent is granted no servers from it"
                        );
                    }
                }
            }
        }

        // Validate every configured risk profile. Each profile stands on
        // its own — there is no "active" or "default" risk profile concept;
        // an agent's `risk_profile` field names exactly which one applies.
        let mut profile_aliases: Vec<&String> = self.risk_profiles.keys().collect();
        profile_aliases.sort();
        for profile_alias in profile_aliases {
            let profile = &self.risk_profiles[profile_alias];
            for (i, env_name) in profile.shell_env_passthrough.iter().enumerate() {
                if !is_valid_env_var_name(env_name) {
                    anyhow::bail!(
                        "risk_profiles.{profile_alias}.shell_env_passthrough[{i}] is invalid ({env_name}); expected [A-Za-z_][A-Za-z0-9_]*"
                    );
                }
            }
        }

        // Security OTP / estop
        if self.security.otp.challenge_max_attempts == 0 {
            validation_bail!(
                InvalidNumericRange,
                "security.otp.challenge_max_attempts",
                "security.otp.challenge_max_attempts must be greater than 0"
            );
        }
        if self.security.otp.token_ttl_secs == 0 {
            validation_bail!(
                InvalidNumericRange,
                "security.otp.token_ttl_secs",

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Rewrite the failing entry as a bare name: "AWS_REGION" instead of "AWS_REGION=us-east-1"
  2. Convert hyphens/dots to underscores (AWS-REGION -> AWS_REGION) and make the first character a letter or underscore
  3. Delete empty-string entries and stray quotes or padding spaces
  4. Fix every profile listed before the one that failed — the loop bails on first offense, so earlier profiles are already clean, later ones may not be

Example fix

# before
[risk_profiles.dev]
shell_env_passthrough = ["AWS_REGION=us-east-1", "npm_config_registry"]

# after
[risk_profiles.dev]
shell_env_passthrough = ["AWS_REGION", "npm_config_registry"]
Defensive patterns

Strategy: validation

Validate before calling

fn valid_env_name(name: &str) -> bool {
    let mut chars = name.chars();
    match chars.next() {
        Some(first) if first.is_ascii_alphabetic() || first == '_' => {}
        _ => return false,
    }
    chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
}

fn passthrough_precheck(cfg: &zeroclaw_config::Config) -> Result<(), String> {
    for profile in cfg.risk_profiles.values() {
        if let Some(bad) = profile.shell_env_passthrough.iter().find(|n| !valid_env_name(n)) {
            return Err(format!("invalid shell_env_passthrough entry: {bad:?}"));
        }
    }
    Ok(())
}

Type guard

fn is_bare_env_var_name(entry: &str) -> bool {
    !entry.contains('=') && valid_env_name(entry)
}

Try / catch

if let Err(err) = config.validate() {
    if err.to_string().contains("shell_env_passthrough") {
        // parse alias and index from the message, rewrite that entry as a bare name
    }
}

Prevention

When it happens

Trigger: Write shell export syntax into the list ("PATH=..."), a hyphenated/dotted name ("AWS-REGION", "aws.region"), a leading digit ("1FOO"), whitespace inside the entry, or an empty string "" in any risk profile's shell_env_passthrough array.

Common situations: Copy-pasting `export KEY=value` lines into the TOML array; pasting Docker `-e KEY=val` fragments; config generators emitting empty-string defaults; team-shared profile aliases where one author assumed bash semantics.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/5a6dee688de1a6d4. Report an issue: GitHub.