{"record":{"id":"60836c553757d1bc","repo":"Hmbown/CodeWhale","slug":"mode-must-not-be-empty","errorCode":null,"errorMessage":"mode must not be empty","messagePattern":"mode must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_threads.rs","lineNumber":7887,"sourceCode":"            && req.model.is_none()\n            && req.mode.is_none()\n            && req.permission_posture.is_none()\n            && req.title.is_none()\n            && req.system_prompt.is_none()\n            && req.workspace.is_none()\n        {\n            bail!(\"At least one thread field is required\");\n        }\n\n        if let Some(model) = req.model.as_ref()\n            && model.trim().is_empty()\n        {\n            bail!(\"model must not be empty\");\n        }\n        if let Some(mode) = req.mode.as_ref()\n            && mode.trim().is_empty()\n        {\n            bail!(\"mode must not be empty\");\n        }\n        if let Some(permission_posture) = req.permission_posture.as_ref()\n            && permission_posture.trim().is_empty()\n        {\n            bail!(\"permission_posture must not be empty\");\n        }\n        if let Some(workspace) = req.workspace.as_ref()\n            && workspace.as_os_str().is_empty()\n        {\n            bail!(\"workspace must not be empty\");\n        }\n\n        // Source resolution reads config files. Do it off the Tokio worker,\n        // then recheck the conversation identity before committing the grant.\n        let shell_policy_workspace = if req.allow_shell == Some(true) || req.workspace.is_some() {\n            let current = self.get_thread(id).await?;\n            if req.allow_shell.unwrap_or(current.allow_shell) {\n                let workspace = req.workspace.clone().unwrap_or(current.workspace);","sourceCodeStart":7869,"sourceCodeEnd":7905,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_threads.rs#L7869-L7905","documentation":"When a thread-update request includes a `mode`, the value must be a non-empty, non-whitespace string. Empty mode strings are rejected so threads never carry an unset/blank mode that downstream policy checks would misinterpret.","triggerScenarios":"Calling update-thread with `mode: Some(\"\".into())` or whitespace-only; deserializing a JSON body like `{\"mode\": \"\"}`.","commonSituations":"A mode selector resets to blank; an integration forwards a mode field from an external source where it was empty; a migration script writes empty strings instead of null.","solutions":["Pass `None` for `mode` to keep the current mode unchanged.","Validate the mode is one of the supported non-empty values before calling the API.","Trim and drop the field if the input is blank."],"exampleFix":"// before\nUpdateThreadRequest { mode: Some(mode_field), .. } // mode_field may be \"\"\n\n// after\nUpdateThreadRequest { mode: Some(mode_field).filter(|m| !m.trim().is_empty()), .. }","handlingStrategy":"validation","validationCode":"if let Some(mode) = &req.mode { if mode.trim().is_empty() { req.mode = None; } }","typeGuard":"fn valid_mode(m: &str) -> bool { !m.trim().is_empty() }","tryCatchPattern":null,"preventionTips":["Constrain mode inputs to a fixed enum/list in the UI","Trim user input before building requests","Send None (field omitted) rather than empty strings"],"tags":["validation","empty-string","mode"],"backgroundTag":"invalid-argument-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}