xai-org/grok-build · error

--permission-mode: invalid value: {e}

Error message

--permission-mode: invalid value: {e}

What it means

In run_single_turn, the --permission-mode CLI flag string is deserialized into the permission-mode enum via serde_json::from_value; any non-enum string produces '--permission-mode: invalid value: {e}' (raised via CliAgentOverrides). It is a pure CLI input validation error, not a runtime condition.

Source

Thrown at crates/codegen/xai-grok-pager/src/headless.rs:837

    );

    apply_agent_flag(&options.agent, &mut agent_config);

    if let Some(ref json) = options.agents_json {
        agent_config.cli_agents = parse_cli_agents(json)?;
    }

    agent_config.cli_agent_overrides = xai_grok_shell::agent::config::CliAgentOverrides {
        tools: parse_comma_list(options.cli_tools.as_deref()),
        disallowed_tools: parse_comma_list(options.cli_disallowed_tools.as_deref()),
        permission_rules: parse_permission_rules_strict(&options.allow_rules, &options.deny_rules)?,
        max_turns: options.max_turns,
        permission_mode: options
            .permission_mode_flag
            .as_deref()
            .map(|s| {
                serde_json::from_value(serde_json::Value::String(s.to_string()))
                    .map_err(|e| anyhow::anyhow!("--permission-mode: invalid value: {e}"))
            })
            .transpose()?,
    };

    if options.trust {
        xai_grok_workspace::folder_trust::grant_folder_trust(&cwd);
    }

    let cancel = CancellationToken::new();
    let memory_config = agent_config.memory_config.clone();
    let mut pending_startup = Some(PendingStartup::new());
    let timer = xai_grok_telemetry::startup::begin(crate::acp::Owner::Client);
    let mut report_startup_failure = |timer: &crate::acp::StartupTimer| {
        timer.emit_telemetry(
            crate::acp::AgentKind::Embedded,
            crate::acp::StartupOutcome::Error,
            None,
            false,

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Use an exact supported value (check --help for the accepted list)
  2. Fix casing — the enum match is typically case-sensitive
  3. Upgrade/downgrade the binary so the flag matches a supported mode
  4. Validate the flag in the wrapper script before invoking

Example fix

// before
pager --permission-mode AcceptEdits
// after
pager --permission-mode accept-edits
Defensive patterns

Strategy: validation

Validate before calling

const VALID_MODES: [&str; 3] = ["default", "accept-edits", "plan"];
fn valid_permission_mode(s: &str) -> bool { VALID_MODES.contains(&s) }

Type guard

fn is_permission_mode(s: &str) -> bool {
    matches!(s, "default" | "accept-edits" | "plan")
}

Try / catch

match serde_json::from_value::<PermissionMode>(serde_json::Value::String(mode.into())) {
    Ok(m) => m,
    Err(e) => { eprintln!("--permission-mode: invalid value: {e}"); std::process::exit(2); }
}

Prevention

When it happens

Trigger: Passing --permission-mode with a value not in the enum (wrong case like 'Default' vs 'default', or a mode the binary does not support such as 'bypassPermissions' on a build without it).

Common situations: Typo or wrong casing in scripts/CI wrappers; copying flags from docs of a different version; shell quoting introducing stray whitespace.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/a7ea7c504fffc794. Report an issue: GitHub.