{"record":{"id":"6460363b232eabcf","repo":"Hmbown/CodeWhale","slug":"invalid-transcript-prose-measure-detail","errorCode":null,"errorMessage":"Invalid transcript.prose_measure: {detail}.","messagePattern":"Invalid transcript\\.prose_measure: (.+?)\\.","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/config.rs","lineNumber":4744,"sourceCode":"                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(transcript) = &self.transcript\n            && let Err(detail) = transcript.prose_measure_columns()\n        {\n            anyhow::bail!(\"Invalid transcript.prose_measure: {detail}.\");\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    /// Resolved prose wrap cap from `[transcript] prose_measure` (#5436).\n    ///\n    /// `None` (absent or `0`) means prose uses the full content width,\n    /// consistent with tool/status cells. Invalid values are rejected by\n    /// [`Config::validate`], which every load path runs, so this resolver\n    /// cannot fail here.\n    #[must_use]\n    pub fn prose_measure(&self) -> Option<u16> {","sourceCodeStart":4726,"sourceCodeEnd":4762,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/config.rs#L4726-L4762","documentation":"Codewhale's Config::validate rejects an invalid [transcript] prose_measure value. prose_measure caps the column width at which the TUI wraps transcript prose (issue #5436); TranscriptConfig::prose_measure_columns accepts only a non-negative integer, where 0 or an absent key means full content width. Any other raw value (string, float, negative number) produces a detail string that validate wraps as 'Invalid transcript.prose_measure: {detail}.'. Every config load path runs validate, so this fails fast at startup or on /config reload.","triggerScenarios":"A config.toml (or --config file or profile) contains [transcript] with prose_measure set to a string (prose_measure = \"80\"), a float (79.5), a negative integer, or any non-integer TOML value. Loading the config, applying a profile, or persisting a /config change calls Config::validate, which hits the anyhow::bail at crates/tui/src/config.rs:4744.","commonSituations":"Copying a quoted number from docs or a chat example; hand-editing ~/.codewhale/config.toml and leaving a typo; migrating an old config that tolerated strings; confusing columns with a percentage or float width.","solutions":["Set prose_measure to a positive whole number of columns, e.g. prose_measure = 80","Set prose_measure = 0 or delete the key to use the full content width","Read the {detail} in the error (it prints the raw value) and fix the [transcript] table in the exact config file in use (~/.codewhale/config.toml, --config path, or profile)"],"exampleFix":"# before (~/.codewhale/config.toml)\n[transcript]\nprose_measure = \"80\"\n\n# after\n[transcript]\nprose_measure = 80","handlingStrategy":"validation","validationCode":"// Before writing/CI-checking a config, verify the value parses as Codewhale expects:\nfn prose_measure_ok(v: &toml::Value) -> bool {\n    match v.as_integer() {\n        Some(n) => n >= 0,\n        None => false, // strings, floats, negatives-as-strings all rejected\n    }\n}\n\nlet ok = cfg.get(\"transcript\")\n    .and_then(|t| t.get(\"prose_measure\"))\n    .map(prose_measure_ok)\n    .unwrap_or(true); // absent = valid\nassert!(ok, \"prose_measure must be a non-negative integer\");","typeGuard":"fn is_valid_prose_measure(v: &toml::Value) -> bool {\n    v.as_integer().is_some_and(|n| n >= 0)\n}","tryCatchPattern":"match config.validate() {\n    Err(e) if e.to_string().starts_with(\"Invalid transcript.prose_measure\") => {\n        eprintln!(\"fix [transcript] prose_measure (positive integer, 0 = full width): {e}\");\n    }\n    rest => rest?,\n}","preventionTips":["Keep prose_measure as an unquoted integer in TOML; never copy quoted examples","Lint checked-in config files in CI with a TOML schema that types prose_measure as u16","0 is the explicit 'full width' value - use it instead of deleting when you want the intent recorded"],"tags":["config","toml","tui","validation"],"backgroundTag":"config-validation-failed","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}