Hmbown/CodeWhale · warning · std::io::Error

Session title cannot exceed {MAX_SESSION_TITLE_CHARS} charac

Error message

Session title cannot exceed {MAX_SESSION_TITLE_CHARS} characters

What it means

normalize_session_title returns InvalidInput when a title exceeds MAX_SESSION_TITLE_CHARS (100), counted in characters (not bytes) after sanitization and trimming. Like the empty-title check, it applies uniformly to the picker, /rename, and PATCH /v1/sessions/{id}.

Source

Thrown at crates/tui/src/session_manager.rs:1917

        .collect()
}

/// Sanitize, trim, and bound a user-supplied session title.
///
/// Returns `InvalidInput` for an empty title or one longer than
/// [`MAX_SESSION_TITLE_CHARS`] so every rename surface (picker, `/rename`,
/// `PATCH /v1/sessions/{id}`) rejects the same inputs with the same reason.
pub fn normalize_session_title(title: &str) -> std::io::Result<String> {
    let sanitized = sanitize_session_title(title);
    let trimmed = sanitized.trim();
    if trimmed.is_empty() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            "Session title cannot be empty",
        ));
    }
    if trimmed.chars().count() > MAX_SESSION_TITLE_CHARS {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            format!("Session title cannot exceed {MAX_SESSION_TITLE_CHARS} characters"),
        ));
    }
    Ok(trimmed.to_string())
}

pub(crate) fn workspace_scope_matches(saved_workspace: &Path, current_workspace: &Path) -> bool {
    if paths_equivalent(saved_workspace, current_workspace) {
        return true;
    }

    // Repository identity comes from the containing checkout itself (Git
    // dir/worktree traversal shared with project-context scope resolution),
    // never from branch names or paths mentioned in conversation.
    let canonical = |path: &Path| fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());
    match (
        find_git_root(&canonical(saved_workspace)),

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Shorten the title to 100 characters or fewer (count characters, not bytes)
  2. Truncate client-side before the rename call if auto-generating titles: title.chars().take(100).collect()
  3. Prefer a concise human title; store longer context elsewhere, not in the title field

Example fix

// before
let title = normalize_session_title(&auto_generated_500_char_summary)?; // InvalidInput

after:
let title = normalize_session_title(
    &auto_generated_500_char_summary.chars().take(100).collect::<String>(),
)?;
Defensive patterns

Strategy: validation

Validate before calling

const LIMIT: usize = codewhale_tui::session_manager::MAX_SESSION_TITLE_CHARS; // 100
let candidate = sanitize_session_title(raw).trim();
if candidate.chars().count() > LIMIT {
    candidate = candidate.chars().take(LIMIT).collect::<String>();
}

Type guard

fn is_title_too_long(e: &std::io::Error) -> bool {
    e.kind() == std::io::ErrorKind::Input
        && e.to_string().contains("cannot exceed")
}

Prevention

When it happens

Trigger: Any rename call with a sanitized, trimmed title longer than 100 chars — e.g. auto-generated titles from a file path or transcript summary, or pasted multi-line text collapsed into one long string.

Common situations: Clients that derive titles from filenames/branch names without a length cap; CJK titles where callers assumed a byte limit; multi-paste concatenation producing one giant string.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/a0381437c8f52c0e. Report an issue: GitHub.