{"record":{"id":"c88103c7d8509979","repo":"Hmbown/CodeWhale","slug":"session-title-cannot-be-empty","errorCode":null,"errorMessage":"Session title cannot be empty","messagePattern":"Session title cannot be empty","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"warning","filePath":"crates/tui/src/session_manager.rs","lineNumber":1911,"sourceCode":"/// OSC 0 terminal title, `codewhale sessions` stdout, and the picker, so the\n/// persisted value must not be able to carry a raw escape sequence. Ordinary\n/// text, punctuation, CJK, and emoji pass through untouched.\npub fn sanitize_session_title(raw: &str) -> String {\n    raw.chars()\n        .filter(|ch| !ch.is_control() && !is_title_format_char(*ch))\n        .collect()\n}\n\n/// Sanitize, trim, and bound a user-supplied session title.\n///\n/// Returns `InvalidInput` for an empty title or one longer than\n/// [`MAX_SESSION_TITLE_CHARS`] so every rename surface (picker, `/rename`,\n/// `PATCH /v1/sessions/{id}`) rejects the same inputs with the same reason.\npub fn normalize_session_title(title: &str) -> std::io::Result<String> {\n    let sanitized = sanitize_session_title(title);\n    let trimmed = sanitized.trim();\n    if trimmed.is_empty() {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidInput,\n            \"Session title cannot be empty\",\n        ));\n    }\n    if trimmed.chars().count() > MAX_SESSION_TITLE_CHARS {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidInput,\n            format!(\"Session title cannot exceed {MAX_SESSION_TITLE_CHARS} characters\"),\n        ));\n    }\n    Ok(trimmed.to_string())\n}\n\npub(crate) fn workspace_scope_matches(saved_workspace: &Path, current_workspace: &Path) -> bool {\n    if paths_equivalent(saved_workspace, current_workspace) {\n        return true;\n    }\n","sourceCodeStart":1893,"sourceCodeEnd":1929,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/session_manager.rs#L1893-L1929","documentation":"normalize_session_title returns InvalidInput when a session title is empty after sanitize_session_title and trim. Every rename surface (the session picker, the /rename command, and PATCH /v1/sessions/{id}) funnels through this one function, so all of them reject the same input with the same message.","triggerScenarios":"Calling a rename API with a title of \"\", whitespace-only input, or a title made entirely of characters the sanitizer strips (control characters, zero-width characters), so nothing printable remains after sanitize+trim.","commonSituations":"A web/API client submits a form with whitespace only; caller validates length before sanitization and misses that sanitization empties the string; double-trim or templating bug produces an empty default title.","solutions":["Send a title containing at least one printable, non-control character","If you control the caller, run trim (and the same sanitization) before submitting so you can give the user a better message than the server error","Check where the empty string comes from — often a template variable or unset field defaulting to blank"],"exampleFix":"// before\nlet title = normalize_session_title(\"   \\u{0}\")?; // InvalidInput\n\n// after\nlet cleaned = sanitize_session_title(raw).trim().to_string();\nif cleaned.is_empty() {\n    return Ok(fallback_title()); // or prompt the user again\n}\nlet title = normalize_session_title(&cleaned)?;","handlingStrategy":"validation","validationCode":"let candidate = sanitize_session_title(raw).trim();\nif candidate.is_empty() {\n    // reject in the UI/form before calling any rename API\n    return Err(own_error(\"title is required\"));\n}","typeGuard":"fn is_empty_title_error(e: &std::io::Error) -> bool {\n    e.kind() == std::io::ErrorKind::InvalidInput && e.to_string().contains(\"cannot be empty\")\n}","tryCatchPattern":"match normalize_session_title(&raw) {\n    Ok(t) => rename(id, &t).await,\n    Err(e) if is_empty_title_error(&e) => show_field_error(\"title\", \"Enter a non-empty title\"),\n    Err(e) => show_field_error(\"title\", &e.to_string()),\n}","preventionTips":["Validate after sanitize+trim, not on the raw string — sanitization can empty a non-empty input","Use HTML/UI required-field checks so users never submit blank titles","Default auto-generated titles to a real value (e.g. first words of the transcript) instead of blank"],"tags":["input-validation","session","rename","rust","empty-string"],"backgroundTag":"empty-string-validation","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}