Hmbown/CodeWhale · error

invalid Runtime Chat virtual thread id

Error message

invalid Runtime Chat virtual thread id

What it means

validate_virtual_thread_id requires virtual thread ids to be exactly 37 bytes, start with "local_thread_", and have a suffix of only ASCII digits and lowercase hex letters (a-f). These ids are locally generated; any other shape means the id was not produced by the local generator and is rejected.

Solutions

  1. Regenerate the id with the local virtual-thread-id generator instead of hand-building one
  2. Fix the prefix to "local_thread_" and pad the suffix to exactly 24 hex/digit chars
  3. Downcase hex digits and remove dashes/punctuation from the suffix
  4. Verify length: 13 (prefix) + 24 (suffix) = 37 characters

Example fix

// before
let id = "local_thread_ABC-123"; // wrong length, uppercase, dashes
// after
let id = "local_thread_0123456789abcdef01234567"; // 13 + 24 = 37 chars
Defensive patterns

Strategy: validation

Validate before calling

fn looks_like_virtual_thread_id(value: &str) -> bool {
    value.len() == 37
        && value.starts_with("local_thread_")
        && value[13..].bytes().all(|b| b.is_ascii_digit() || matches!(b, b'a'..=b'f'))
}

Type guard

fn as_virtual_thread_id(value: &str) -> Option<&str> {
    looks_like_virtual_thread_id(value).then_some(value)
}

Try / catch

if !looks_like_virtual_thread_id(&thread_id) {
    eprintln!("regenerating virtual thread id (got {thread_id:?})");
    let thread_id = generate_virtual_thread_id();
}

Prevention

When it happens

Trigger: Calling validate_virtual_thread_id (directly or via RelayState::validate over bindings) with an id that is not 37 chars, lacks the "local_thread_" prefix, or whose 24-char suffix contains uppercase hex, 'g'-'z', punctuation, or spaces.

Common situations: Constructing a virtual thread id by hand in tests or tooling with the wrong length or prefix; passing a server- or provider-side thread id (e.g. a UUID with dashes or uppercase) where a local id is required; truncation of a valid id.

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/5ce84429bee25927. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/runtime_chat_relay.rs:1717

    Ok(())
}

fn validate_operation_key(value: &str) -> Result<()> {
    validate_relay_id(value, "operation key")?;
    if value.len() > MAX_OPERATION_KEY_BYTES {
        bail!("Runtime Chat operation key is too long");
    }
    Ok(())
}

fn validate_virtual_thread_id(value: &str) -> Result<()> {
    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

View on GitHub (pinned to 73e0f67d83)