Hmbown/CodeWhale · error

invalid Runtime Chat

Error message

invalid Runtime Chat {label}

What it means

validate_relay_id is the shared identifier validator for Runtime Chat relay ids (run id, route labels, operation keys, etc.). It rejects values that are empty, too long, contain "://", or contain any byte outside the allowed ASCII set (alphanumeric plus . _ : @ / + ~ -). The bail includes the caller-provided label, e.g. "invalid Runtime Chat run id".

Solutions

  1. Strip the scheme from URLs and pass only the bare id portion (remove "://...")
  2. Replace disallowed characters with allowed ones (. _ : @ / + ~ - or alphanumeric)
  3. Check that the value is non-empty before validating
  4. Restrict upstream input to ASCII identifiers (e.g. a regex like ^[A-Za-z0-9._:@/+~-]+$)

Example fix

// before
let id = "https://example.com/run/abc"; // contains "://"
// after
let id = "example.com/run/abc";
Defensive patterns

Strategy: validation

Validate before calling

const RELAY_ID_RE: once_cell::sync::Lazy<regex::Regex> = once_cell::sync::Lazy::new(
    || regex::Regex::new(r"^[A-Za-z0-9._:@/+~-]+$").unwrap(),
);
fn is_valid_relay_id(value: &str) -> bool {
    !value.is_empty() && !value.contains("://") && RELAY_ID_RE.is_match(value)
}

Type guard

fn as_relay_id(value: &str) -> Option<&str> {
    (!value.is_empty()
        && !value.contains("://")
        && value.bytes().all(|b| b.is_ascii_alphanumeric()
            || matches!(b, b'.' | b'_' | b':' | b'@' | b'/' | b'+' | b'~' | b'-')))
    .then_some(value)
}

Try / catch

match validate_relay_id(&id, "run id") {
    Ok(()) => { /* proceed */ }
    Err(e) => {
        eprintln!("{e}: sanitizing id before use");
        let id = sanitize_relay_id(&id); // strip scheme, replace bad chars
    }
}

Prevention

When it happens

Trigger: Any validate_relay_id(value, label) call (directly or via validate_operation_key, validate_relay_id wrappers in validate()) receiving a value that is empty, contains "://", or has disallowed characters (spaces, Unicode, control bytes, %, ?, &, etc.).

Common situations: Passing a full URL where a bare id is expected (the "://" check specifically catches this); user-supplied thread or route names with spaces or non-ASCII characters; ids with percent-encoding or query strings; empty strings from failed lookups.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

    #[cfg(test)]
    if take_state_persist_failure(path) {
        bail!("injected Runtime Chat state persistence failure");
    }
    let body = serde_json::to_vec(state).context("encode Runtime Chat binding state")?;
    crate::utils::write_atomic(path, &body).context("persist Runtime Chat binding state")
}

fn validate_relay_id(value: &str, label: &str) -> Result<()> {
    if value.is_empty()
        || value.len() > MAX_RELAY_ID_BYTES
        || value.contains("..")
        || value.contains("://")
        || !value.bytes().all(|byte| {
            byte.is_ascii_alphanumeric()
                || matches!(byte, b'.' | b'_' | b':' | b'@' | b'/' | b'+' | b'~' | b'-')
        })
    {
        bail!("invalid Runtime Chat {label}");
    }
    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'))

View on GitHub (pinned to 73e0f67d83)