Hmbown/CodeWhale · error · anyhow::Error
Invalid approval_policy '{policy}': expected on-request, unt
Error message
Invalid approval_policy '{policy}': expected on-request, untrusted, never, auto, or suggest. What it means
Config::validate() normalizes approval_policy (trim + ASCII lowercase) and requires one of on-request, untrusted, never, auto, or suggest. Any other string fails validation at startup with this message. Case and surrounding whitespace are tolerated; the keyword itself must match exactly.
Source
Thrown at crates/tui/src/config.rs:4421
let provider = self.api_provider();
let known = model_completion_names_for_provider(provider);
let hint = if known.is_empty() {
String::new()
} else {
format!(" (for example: {})", known.join(", "))
};
anyhow::bail!(
"Invalid default_text_model '{model}' for provider '{}': expected auto or a model ID this provider serves{hint}.",
provider.as_str()
);
}
if let Some(policy) = self.approval_policy.as_deref() {
let normalized = policy.trim().to_ascii_lowercase();
if !matches!(
normalized.as_str(),
"on-request" | "untrusted" | "never" | "auto" | "suggest"
) {
anyhow::bail!(
"Invalid approval_policy '{policy}': expected on-request, untrusted, never, auto, or suggest."
);
}
}
if let Some(v) = self.verbosity.as_deref() {
let normalized = v.trim().to_ascii_lowercase();
if !matches!(normalized.as_str(), "normal" | "concise") {
anyhow::bail!("Invalid verbosity '{v}': expected normal or concise.");
}
}
if let Some(mode) = self.sandbox_mode.as_deref() {
let normalized = mode.trim().to_ascii_lowercase();
if !matches!(
normalized.as_str(),
"read-only" | "workspace-write" | "danger-full-access" | "external-sandbox"
) {
anyhow::bail!(
"Invalid sandbox_mode '{mode}': expected read-only, workspace-write, danger-full-access, or external-sandbox."View on GitHub (pinned to 8880682c63)
Solutions
- Set approval_policy to one of: on-request, untrusted, never, auto, suggest (hyphenated, lowercase).
- Remove the key entirely if the built-in default is acceptable.
- Check for a duplicate approval_policy key elsewhere in the TOML overriding your fix.
Example fix
# before approval_policy = "on_request" # after approval_policy = "on-request"
Defensive patterns
Strategy: validation
Validate before calling
const APPROVAL_POLICIES: &[&str] = &["on-request", "untrusted", "never", "auto", "suggest"];
fn approval_policy_is_valid(raw: &str) -> bool {
APPROVAL_POLICIES.contains(&raw.trim().to_ascii_lowercase().as_str())
}
if let Some(p) = &config.approval_policy {
anyhow::ensure!(approval_policy_is_valid(p), "bad approval_policy");
} Type guard
fn is_valid_approval_policy(raw: &str) -> bool {
matches!(
raw.trim().to_ascii_lowercase().as_str(),
"on-request" | "untrusted" | "never" | "auto" | "suggest"
)
} Try / catch
if let Err(e) = config.validate() {
if let Some(rest) = e.to_string().strip_prefix("Invalid approval_policy ") {
// `rest` names the offending value; offer the allowed list and re-validate
} else {
return Err(e);
}
} Prevention
- Use hyphens, not underscores, in policy keywords.
- Generate config from constants/enums in tooling instead of hand-typed strings.
- Lint committed config.toml files against the allowed vocabulary in CI.
When it happens
Trigger: Writing approval_policy = "on_request" (underscore instead of hyphen), "always", "ask", or "when-needed" in config.toml; passing a policy string copied from a different tool's config.
Common situations: Migrating configs from other CLI agents whose policy vocabularies differ; hyphen/underscore confusion; abbreviations like 'req' typed from memory.
Related errors
- Invalid default_text_model '{model}' for provider '{}': expe
- Invalid verbosity '{v}': expected normal or concise.
- Invalid sandbox_mode '{mode}': expected read-only, workspace
- Invalid tui.alternate_screen '{mode}': expected auto, always
- unavailable credential
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/279e5c814d90d392.
Report an issue: GitHub.