{"record":{"id":"004e364897444858","repo":"Hmbown/CodeWhale","slug":"invalid-label","errorCode":null,"errorMessage":"invalid {label}","messagePattern":"invalid (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_chat_relay.rs","lineNumber":1741,"sourceCode":"    if value.len() != 35\n        || !value.starts_with(\"local_turn_\")\n        || !value[11..]\n            .bytes()\n            .all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f'))\n    {\n        bail!(\"invalid Runtime Chat virtual turn id\");\n    }\n    Ok(())\n}\n\nfn validate_native_record_id(value: &str, label: &str) -> Result<()> {\n    if value.len() < 5\n        || value.len() > 80\n        || !value\n            .bytes()\n            .all(|byte| byte.is_ascii_alphanumeric() || byte == b'_')\n    {\n        bail!(\"invalid {label}\");\n    }\n    Ok(())\n}\n\nfn validate_route_id(value: &str, label: &str) -> Result<()> {\n    if !crate::runtime_api::runtime_chat_route_id_is_safe(value) {\n        bail!(\"invalid Runtime Chat {label}\");\n    }\n    Ok(())\n}\n\nfn validate_model_id(value: &str) -> Result<()> {\n    if !crate::runtime_api::runtime_chat_model_id_is_safe(value) {\n        bail!(\"invalid Runtime Chat model id\");\n    }\n    Ok(())\n}\n","sourceCodeStart":1723,"sourceCodeEnd":1759,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_chat_relay.rs#L1723-L1759","documentation":"validate_native_record_id validates native (provider-side) record ids: length 5–80 bytes, composed only of ASCII alphanumerics and underscore. The bail message uses the caller-supplied label (e.g. \"invalid native turn id\"). It exists because native ids become state keys and filesystem-adjacent identifiers, so only a conservative charset is accepted.","triggerScenarios":"Calling validate_native_record_id(value, label) — for native turn ids or other native records — with a value shorter than 5, longer than 80, or containing dashes, dots, colons, spaces, Unicode, or other non-[A-Za-z0-9_] characters.","commonSituations":"Passing provider ids that use dashes (common UUID forms) or dots where only alphanumerics/underscore are allowed; empty or near-empty strings from failed provider responses; very long composite ids over 80 bytes.","solutions":["Normalize the provider id to [A-Za-z0-9_] only (replace dashes/dots with underscores) before validating","Confirm the id is genuinely from the provider and non-degenerate (≥5 chars)","Truncate or hash composite ids to stay within 80 bytes","If a legitimate provider id format is being rejected, widen the validator's charset in code with a test"],"exampleFix":"// before\nlet id = \"turn_9f86d081-884c-7d65\"; // dashes not allowed\n// after\nlet id = \"turn_9f86d081_884c_7d65\"; // alphanumerics + underscore only","handlingStrategy":"validation","validationCode":"fn looks_like_native_record_id(value: &str) -> bool {\n    (5..=80).contains(&value.len())\n        && value.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_')\n}\nfn normalize_native_record_id(raw: &str) -> String {\n    let cleaned: String = raw.chars().map(|c| if c.is_ascii_alphanumeric() { c } else { '_' }).collect();\n    cleaned.chars().take(80).collect()\n}","typeGuard":"fn as_native_record_id(value: &str) -> Option<&str> {\n    looks_like_native_record_id(value).then_some(value)\n}","tryCatchPattern":"if !looks_like_native_record_id(&native_id) {\n    let native_id = normalize_native_record_id(&native_id);\n    validate_native_record_id(&native_id, \"native turn id\")?;\n}","preventionTips":["Normalize provider ids (dashes/dots to underscores) before storing them as native record ids","Reject empty/degenerate ids at the provider-response boundary rather than at persist time","Keep composite ids within 80 bytes; hash when concatenating long parts"],"tags":["validation","identifier","charset"],"backgroundTag":"invalid-identifier-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}