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
- Replace the value with one of: read, write, shell, external, publish, destructive
- If the intent has no matching class, scope by tool = "<tool-id>" instead
- 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
- Copy the enumerated list from the error message, not from memory
- Note casing and hyphens normalize; only the value itself must be known
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
- Invalid auto_review.{kind}[{index}].text_contains: user-inte
- Invalid auto_review.{kind}[{index}]: set at least one of too
- Invalid auto_review.allow[{index}].action_kind '{action_kind
- ${name} is required
- ${names.join(" or ")} is required
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/080c616f0ea7003e.
Report an issue: GitHub.