Hmbown/CodeWhale · error · anyhow::Error
Invalid cost_currency
Error message
Invalid cost_currency '{other}': expected usd, cny, rmb, or yuan What it means
Thrown by CostCurrencyValue::from_setting when the cost_currency setting, after trim and ASCII lowercasing, is not one of usd, cny, rmb, or yuan. cny/rmb/yuan all map to Cny; only these four spellings are accepted and there is no empty-string default, so a blank value also fails.
Solutions
- Set cost_currency to "usd", "cny", "rmb", or "yuan" (case-insensitive)
- If you need another currency, request it upstream; do not keep an unsupported value in config
- Remove typos or trailing punctuation from the value
Example fix
# before cost_currency = "eur" # after cost_currency = "usd"
Defensive patterns
Strategy: validation
Validate before calling
fn normalize_cost_currency(value: &str) -> Option<&'static str> {
match value.trim().to_ascii_lowercase().as_str() {
"usd" => Some("usd"),
"cny" | "rmb" | "yuan" => Some("cny"),
_ => None,
}
}
// before saving:
let Some(currency) = normalize_cost_currency(input) else {
return Err(anyhow::anyhow!("cost_currency must be usd, cny, rmb, or yuan"));
}; Prevention
- Use a closed dropdown of the four accepted spellings instead of free-form input
- Normalize at write time (trim + lowercase) so reads never see "USD " variants
- Treat empty as invalid: pick an explicit default currency in the UI
When it happens
Trigger: Setting cost_currency to anything else: "eur", "jpy", "us", or "" (empty). Triggered wherever from_setting parses the setting during config load.
Common situations: Hand-editing config with an ISO code that was never supported; clearing the value instead of using "usd"; scripts writing uppercase with different spacing ("USD " is fine after trim, but "US D" is not).
Related errors
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/da293e71c57d50c8.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/config_ui.rs:1303
}
#[allow(dead_code)]
fn description(self) -> &'static str {
match self {
Self::Agent => "Do the work in this session.",
Self::Plan => "Design first; implement after you approve.",
Self::Operate => "Dispatch workers; keep the parent free for steers.",
}
}
}
impl CostCurrencyValue {
fn from_setting(value: &str) -> Result<Self> {
match value.trim().to_ascii_lowercase().as_str() {
"usd" => Ok(Self::Usd),
"cny" | "rmb" | "yuan" => Ok(Self::Cny),
other => {
anyhow::bail!("Invalid cost_currency '{other}': expected usd, cny, rmb, or yuan")
}
}
}
fn as_setting(self) -> &'static str {
match self {
Self::Usd => "usd",
Self::Cny => "cny",
}
}
}
impl From<ApprovalMode> for ApprovalModeValue {
fn from(value: ApprovalMode) -> Self {
match value {
ApprovalMode::Auto => Self::Auto,
ApprovalMode::Bypass => Self::Bypass,
ApprovalMode::Suggest => Self::Suggest,View on GitHub (pinned to 0c42157ee5)