{"record":{"id":"89828c75376ba82d","repo":"Hmbown/CodeWhale","slug":"invalid-tui-alternate-screen-mode-expected-au","errorCode":null,"errorMessage":"Invalid tui.alternate_screen '{mode}': expected auto, always, or never.","messagePattern":"Invalid tui\\.alternate_screen '(.+?)': expected auto, always, or never\\.","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/config.rs","lineNumber":4448,"sourceCode":"            }\n        }\n        if let Some(mode) = self.sandbox_mode.as_deref() {\n            let normalized = mode.trim().to_ascii_lowercase();\n            if !matches!(\n                normalized.as_str(),\n                \"read-only\" | \"workspace-write\" | \"danger-full-access\" | \"external-sandbox\"\n            ) {\n                anyhow::bail!(\n                    \"Invalid sandbox_mode '{mode}': expected read-only, workspace-write, danger-full-access, or external-sandbox.\"\n                );\n            }\n        }\n        if let Some(tui) = &self.tui\n            && let Some(mode) = tui.alternate_screen.as_deref()\n        {\n            let mode = mode.to_ascii_lowercase();\n            if !matches!(mode.as_str(), \"auto\" | \"always\" | \"never\") {\n                anyhow::bail!(\n                    \"Invalid tui.alternate_screen '{mode}': expected auto, always, or never.\"\n                );\n            }\n        }\n        if let Some(auto_review) = &self.auto_review {\n            auto_review.validate()?;\n        }\n        if let Some(providers) = &self.providers {\n            providers.validate()?;\n        }\n        Ok(())\n    }\n\n    #[must_use]\n    pub fn api_provider(&self) -> ApiProvider {\n        // #1519 safety fix: when `provider = \"<name>\"` is not a built-in provider\n        // but names a `[providers.<name>]` custom table, route as the dynamic\n        // custom identity. Exact configured keys win even when their spelling","sourceCodeStart":4430,"sourceCodeEnd":4466,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/config.rs#L4430-L4466","documentation":"Config::validate() requires tui.alternate_screen to be auto, always, or never. Unlike the neighboring checks, the value is lowercased but NOT trimmed, so leading/trailing whitespace also fails. Boolean-style strings are the most common mistake because the key sounds boolean.","triggerScenarios":"Setting [tui] alternate_screen = \"true\"/\"false\"/\"yes\"; a value with stray whitespace such as \"always \" (not trimmed by this check); copy from an older config schema that used booleans.","commonSituations":"Users assume a display toggle accepts true/false; terminal-wrapper scripts (tmux, emacs) prompt users to disable the alternate screen and they guess the wrong vocabulary.","solutions":["Set alternate_screen = \"auto\" | \"always\" | \"never\" (string, not boolean).","Ensure no leading/trailing whitespace in the value.","If the terminal wrapper mishandles the alternate screen, \"never\" is usually the intended fix."],"exampleFix":"# before\n[tui]\nalternate_screen = \"false\"\n\n# after\n[tui]\nalternate_screen = \"never\"","handlingStrategy":"validation","validationCode":"fn alternate_screen_is_valid(raw: &str) -> bool {\n    // mirror the exact check: lowercase only, NO trim\n    matches!(raw.to_ascii_lowercase().as_str(), \"auto\" | \"always\" | \"never\")\n}\n\nif let Some(tui) = &config.tui {\n    if let Some(mode) = tui.alternate_screen.as_deref() {\n        anyhow::ensure!(alternate_screen_is_valid(mode), \"tui.alternate_screen must be auto/always/never\");\n    }\n}","typeGuard":"fn is_valid_alternate_screen(raw: &str) -> bool {\n    matches!(raw.to_ascii_lowercase().as_str(), \"auto\" | \"always\" | \"never\")\n}","tryCatchPattern":"match config.validate() {\n    Err(e) if e.to_string().starts_with(\"Invalid tui.alternate_screen\") => {\n        config.tui.as_mut().map(|t| t.alternate_screen = None);\n        config.validate()?\n    }\n    other => other,\n}","preventionTips":["Use the string keywords auto/always/never — never booleans.","Watch for stray whitespace: this field is lowercased but not trimmed.","When embedding in terminal wrappers, test with the actual wrapper before committing config."],"tags":["rust","config","toml","validation","tui","terminal"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}