Hmbown/CodeWhale · error · anyhow::Error

Invalid auto_review.{kind}[{index}].action_kind '{action_kin

Error message

Invalid auto_review.{kind}[{index}].action_kind '{action_kind}': expected read, write, shell, external, publish, or destructive.

What it means

An auto_review rule's action_kind failed to parse after normalization (trim, lowercase, '-' to '_'): crates/tui/src/config.rs:3042 accepts exactly read, write, shell, external, publish, or destructive (plus parse_auto_review_action_kind aliases such as mcp_read for read). The invalid value is echoed in the message.

Source

Thrown at crates/tui/src/config.rs:3042

    for (index, rule) in rules.iter().enumerate() {
        if rule
            .text_contains
            .as_deref()
            .is_some_and(|value| !value.trim().is_empty())
        {
            anyhow::bail!(
                "Invalid auto_review.{kind}[{index}].text_contains: user-intent matching was retired; scope the rule with tool and/or action_kind."
            );
        }
        if !rule.has_matcher() {
            anyhow::bail!(
                "Invalid auto_review.{kind}[{index}]: set at least one of tool or action_kind."
            );
        }
        if let Some(action_kind) = rule.action_kind.as_deref() {
            let normalized = action_kind.trim().to_ascii_lowercase().replace('-', "_");
            if parse_auto_review_action_kind(&normalized).is_none() {
                anyhow::bail!(
                    "Invalid auto_review.{kind}[{index}].action_kind '{action_kind}': expected read, write, shell, external, publish, or destructive."
                );
            }
            if kind == "allow"
                && !matches!(
                    normalized.as_str(),
                    "read" | "write" | "shell" | "external" | "publish" | "destructive"
                )
            {
                anyhow::bail!(
                    "Invalid auto_review.allow[{index}].action_kind '{action_kind}': this retired narrow kind cannot safely widen to a v0.9.8 decision class; replace it with an exact tool rule or a current action_kind."
                );
            }
        }
    }
    Ok(())
}

View on GitHub (pinned to 8880682c63)

Solutions

  1. Replace the value with one of: read, write, shell, external, publish, destructive
  2. If the intent has no matching class, scope by tool = "<tool-id>" instead
  3. Re-run config load to confirm

Example fix

# config.toml - before
[[auto_review.deny]]
action_kind = "exec"

# config.toml - after
[[auto_review.deny]]
action_kind = "shell"
Defensive patterns

Strategy: validation

Validate before calling

const ACTION_KINDS: [&str; 6] = ["read","write","shell","external","publish","destructive"];
fn valid_action_kind(k: &str) -> bool {
    ACTION_KINDS.contains(&k.trim().to_ascii_lowercase().replace('-', "_").as_str())
}

Type guard

fn parse_action_kind(raw: &str) -> Option<&'static str> {
    let n = raw.trim().to_ascii_lowercase().replace('-', "_");
    match n.as_str() { "read"|"mcp_read" => Some("read"), "write" => Some("write"), "shell" => Some("shell"), "external" => Some("external"), "publish" => Some("publish"), "destructive" => Some("destructive"), _ => None }
}

Try / catch

// Validate the enum before writing config files programmatically
let kind = parse_action_kind(user_input).ok_or_else(|| anyhow!("unknown action_kind {user_input}"))?;

Prevention

When it happens

Trigger: A typo, a retired kind name (e.g. 'exec', 'net'), or a made-up class from older docs; casing and hyphens are fine ('Shell' and 'content-publish' normalize correctly).

Common situations: Configs migrated between versions where kind names changed; guesswork values instead of copying the enumerated list.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/080c616f0ea7003e. Report an issue: GitHub.