{"record":{"id":"91b756c6d7bf8720","repo":"Hmbown/CodeWhale","slug":"failed-to-update-setting-invalid-key-value","errorCode":null,"errorMessage":"Failed to update setting: invalid {key} '{value}'. Expected a number from 10 to 100.","messagePattern":"Failed to update setting: invalid (.+?) '(.+?)'\\. Expected a number from 10 to 100\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/settings.rs","lineNumber":2599,"sourceCode":"    let parsed = value\n        .trim()\n        .parse::<u16>()\n        .map_err(|_| anyhow::anyhow!(\"Invalid {key} '{value}': expected {min}-{max}\"))?;\n    if !(min..=max).contains(&parsed) {\n        anyhow::bail!(\"Invalid {key} '{value}': expected {min}-{max}\");\n    }\n    Ok(parsed)\n}\n\nfn parse_percent_setting(key: &str, value: &str) -> Result<f64> {\n    let trimmed = value.trim().trim_end_matches('%').trim();\n    let percent = trimmed.parse::<f64>().map_err(|_| {\n        anyhow::anyhow!(\n            \"Failed to update setting: invalid {key} '{value}'. Expected a number from 10 to 100.\"\n        )\n    })?;\n    if !(10.0..=100.0).contains(&percent) {\n        anyhow::bail!(\n            \"Failed to update setting: invalid {key} '{value}'. Expected a number from 10 to 100.\"\n        );\n    }\n    Ok(percent)\n}\n\nfn normalize_mention_menu_behavior(value: &str) -> Result<String> {\n    match value.trim().to_ascii_lowercase().as_str() {\n        \"fuzzy\" | \"default\" => Ok(\"fuzzy\".to_string()),\n        \"browser\" | \"browse\" | \"file-browser\" | \"file_browser\" => Ok(\"browser\".to_string()),\n        _ => {\n            anyhow::bail!(\n                \"Failed to update setting: invalid mention_menu_behavior '{value}'. Expected: fuzzy, browser.\"\n            )\n        }\n    }\n}\n","sourceCodeStart":2581,"sourceCodeEnd":2617,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/settings.rs#L2581-L2617","documentation":"Thrown by parse_percent_setting for percentage-style settings. The value is trimmed, one trailing '%' is stripped, parsed as f64, then required to lie within 10.0..=100.0. Parse failures and out-of-range values bail with the identical message, so the cause is ambiguous from the text alone.","triggerScenarios":"':set context_percent 5' (below 10), ':set context_percent 150' (above 100), ':set context_percent abc', or a double percent '10%%' where only one trailing % is stripped and the second breaks the f64 parse.","commonSituations":"Users trying to reserve tiny contexts (5%), values above 100 assuming oversubscription works, locale-style decimal commas ('12,5'), and trailing junk after the number ('50 x').","solutions":["Send a number between 10 and 100 inclusive; a single trailing % is optional.","Use a dot for decimals, not a comma.","If you genuinely need below 10%, that is out of contract by design; use 10 or reconsider which setting you need.","Pre-validate in the caller: trim, strip one %, parse f64, range-check 10..=100."],"exampleFix":"# before\n:set context_percent 5%\n\n# after\n:set context_percent 10%","handlingStrategy":"validation","validationCode":"fn valid_percent(v: &str) -> bool {\n    let t = v.trim().trim_end_matches('%').trim();\n    matches!(t.parse::<f64>(), Ok(p) if (10.0..=100.0).contains(&p))\n}","typeGuard":null,"tryCatchPattern":"match parse_percent_setting(key, value) {\n    Err(err) if err.to_string().contains(\"number from 10 to 100\") => clamp_or_reprompt(),\n    other => other?,\n}","preventionTips":["Strip one trailing '%' and use a dot decimal before submitting.","Treat sub-10 percentages as out of contract rather than retrying variations.","Validate percent fields in config UIs with the same 10..=100 window."],"tags":["settings","percent","range","validation","tui","rust"],"backgroundTag":"percent-config-out-of-range","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}