{"record":{"id":"e72983467e309f97","repo":"Hmbown/CodeWhale","slug":"session-title-cannot-exceed-characters","errorCode":null,"errorMessage":"Session title cannot exceed {} characters","messagePattern":"Session title cannot exceed (.+?) characters","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":3009,"sourceCode":"        .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\n    // Repository identity comes from the containing checkout itself (Git\n    // dir/worktree traversal shared with project-context scope resolution),\n    // never from branch names or paths mentioned in conversation.\n    let canonical = |path: &Path| fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());\n    match (\n        find_git_root(&canonical(saved_workspace)),","sourceCodeStart":2991,"sourceCodeEnd":3027,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_manager.rs#L2991-L3027","documentation":"Session titles are normalized by `normalize_session_title` (crates/tui/src/session_manager.rs:3008), which trims whitespace, rejects empty titles, and rejects titles longer than MAX_SESSION_TITLE_CHARS (100 chars, counted per Unicode char). Any rename or create surface that passes an over-long title gets this InvalidInput io::Error. The `{}` in the message is the constant bound (100), so the rendered message states the exact limit.","triggerScenarios":"Calling any session-rename or session-create API (picker rename, `/rename` command, SessionManager::rename) with a title whose trimmed text is more than 100 Unicode characters.","commonSituations":"Pasting a long file path, commit message, or conversation excerpt as a session title; renaming a session from a script that builds titles programmatically; multi-byte input where byte length feels small but char count exceeds 100.","solutions":["Shorten the title to 100 characters or fewer (counting chars, not bytes).","Truncate before calling the API, e.g. title.chars().take(MAX_SESSION_TITLE_CHARS).collect::<String>().","For scripted renames, validate the length first and surface a clear message instead of the io::Error."],"exampleFix":"// before\nmanager.rename(id, long_title)?;\n// after\nlet short: String = long_title.trim().chars().take(100).collect();\nmanager.rename(id, short)?;","handlingStrategy":"validation","validationCode":"fn valid_title(t: &str) -> bool {\n    let trimmed = t.trim();\n    !trimmed.is_empty() && trimmed.chars().count() <= 100\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Truncate titles to 100 chars with .chars().take(100) before any rename call.","Count characters (not bytes) for length limits.","Trim user input before validation."],"tags":["validation","input-length","io-error"],"backgroundTag":"value-out-of-range","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"}