Hmbown/CodeWhale · error
invalid Runtime Chat virtual turn id
Error message
invalid Runtime Chat virtual turn id
What it means
validate_virtual_turn_id requires virtual turn ids to be exactly 35 bytes, start with "local_turn_", and have a suffix of only ASCII digits and lowercase hex letters. Like virtual thread ids, these must come from the local generator; any other shape is rejected.
Solutions
- Generate the id with the local virtual-turn-id generator
- Fix the prefix to "local_turn_" and make the suffix exactly 23 hex/digit chars
- Downcase hex and strip dashes/punctuation from the suffix
- Verify length: 11 (prefix) + 23 (suffix) = 35 characters
Example fix
// before let id = "local_turn_42"; // too short // after let id = "local_turn_0123456789abcdef0123456"; // 11 + 23 = 35 chars
Defensive patterns
Strategy: validation
Validate before calling
fn looks_like_virtual_turn_id(value: &str) -> bool {
value.len() == 35
&& value.starts_with("local_turn_")
&& value[11..].bytes().all(|b| b.is_ascii_digit() || matches!(b, b'a'..=b'f'))
} Type guard
fn as_virtual_turn_id(value: &str) -> Option<&str> {
looks_like_virtual_turn_id(value).then_some(value)
} Try / catch
if !looks_like_virtual_turn_id(&turn_id) {
eprintln!("regenerating virtual turn id (got {turn_id:?})");
let turn_id = generate_virtual_turn_id();
} Prevention
- Only create virtual turn ids with the local generator
- Keep the 11+23=35 length invariant in a constructor function
- Do not substitute provider message ids for virtual turn ids
When it happens
Trigger: Calling validate_virtual_turn_id (directly or via RelayState::validate over binding turns) with an id that is not 35 chars, lacks the "local_turn_" prefix, or whose 23-char suffix contains uppercase, non-hex letters, or punctuation.
Common situations: Hand-built turn ids in tests/tooling with wrong length; using a message or provider turn id where a locally generated id is required; string truncation or accidental whitespace.
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 preallocated task id: expected task_<16hex>
- invalid Runtime Chat
- invalid Runtime Chat virtual thread id
- cloud job id must look like cloud_
- CRON field contains an empty list item
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/d12b2b580d092352.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/runtime_chat_relay.rs:1729
if value.len() != 37
|| !value.starts_with("local_thread_")
|| !value[13..]
.bytes()
.all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f'))
{
bail!("invalid Runtime Chat virtual thread id");
}
Ok(())
}
fn validate_virtual_turn_id(value: &str) -> Result<()> {
if value.len() != 35
|| !value.starts_with("local_turn_")
|| !value[11..]
.bytes()
.all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f'))
{
bail!("invalid Runtime Chat virtual turn id");
}
Ok(())
}
fn validate_native_record_id(value: &str, label: &str) -> Result<()> {
if value.len() < 5
|| value.len() > 80
|| !value
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || byte == b'_')
{
bail!("invalid {label}");
}
Ok(())
}
fn validate_route_id(value: &str, label: &str) -> Result<()> {
if !crate::runtime_api::runtime_chat_route_id_is_safe(value) {View on GitHub (pinned to 73e0f67d83)