Hmbown/CodeWhale · error

Invalid session id

Error message

Invalid session id '{id}'

What it means

validated_session_id enforces that a session id contains only ASCII alphanumerics, hyphens, and underscores; anything else yields InvalidInput with 'Invalid session id'. This keeps ids safe to embed directly into file names across filesystems. The error names the offending id (after trimming) so the caller can see the disallowed characters.

Solutions

  1. Sanitize the id: replace invalid characters with '-' or '_' before use
  2. Use a generator that produces conforming ids (alphanumeric/hyphen/underscore), e.g. a plain UUID without braces
  3. Show the user the allowed character set when accepting ids interactively

Example fix

// before
let id = format!("{}", uuid);
// after
let id: String = uuid.simple().to_string(); // plain hex, no braces/hyphens
// or sanitize: id.chars().map(|c| if c.is_ascii_alphanumeric() || c=='-' || c=='_' { c } else { '_' }).collect()
Defensive patterns

Strategy: validation

Validate before calling

let ok = id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_') && !id.trim().is_empty();
if !ok { return Err(anyhow!("id must be [A-Za-z0-9_-]")); }

Type guard

fn is_safe_session_id(id: &str) -> bool {
    !id.trim().is_empty()
        && id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
}

Try / catch

match manager.checkpoint_path(&user_id) {
    Ok(p) => use(p),
    Err(e) if e.kind() == io::ErrorKind::InvalidInput => eprintln!("Invalid id '{}': use A-Z a-z 0-9 - _ only", user_id),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling validated_session_id (or any API that routes through it, like checkpoint_path) with an id containing spaces, slashes, dots, unicode, or other punctuation — e.g. a UUID with braces or a user-typed name like 'my session/1'.

Common situations: Passing an untrimmed path fragment as an id; deriving ids from free-form user input or foreign /load file names; using a UUID variant with curly braces or colons.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/b915724ebd2db744. Report an issue: GitHub.

Appendix: source

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

    /// session without consulting the model transcript.
    #[cfg_attr(not(test), expect(dead_code))]
    pub(crate) fn replay_approvals(&self, session_id: &str) -> io::Result<ApprovalReplay> {
        self.approval_receipt_store().replay(session_id)
    }

    fn validated_session_id<'a>(&self, id: &'a str) -> std::io::Result<&'a str> {
        let trimmed = id.trim();
        if trimmed.is_empty() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "Session id cannot be empty",
            ));
        }
        if !trimmed
            .chars()
            .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
        {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!("Invalid session id '{id}'"),
            ));
        }
        if trimmed == SESSION_BOOT_OWNERS_STEM {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!("Session id '{trimmed}' collides with a reserved sessions file"),
            ));
        }
        Ok(trimmed)
    }

    fn validated_session_path(&self, id: &str) -> std::io::Result<PathBuf> {
        let trimmed = self.validated_session_id(id)?;
        Ok(self.sessions_dir.join(format!("{trimmed}.json")))
    }

View on GitHub (pinned to 73e0f67d83)