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
- Sanitize the id: replace invalid characters with '-' or '_' before use
- Use a generator that produces conforming ids (alphanumeric/hyphen/underscore), e.g. a plain UUID without braces
- 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
- Sanitize free-form user input into the allowed charset before passing it as an id
- Use brace-free UUIDs (uuid.simple()) rather than braced forms
- Document the id charset wherever users can name sessions
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
- Invalid durable task id
- Invalid task execution identity
- Session id cannot be empty
- Session id ' ' collides with a reserved sessions file
- A pinned task provider requires an explicit model
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)