{"record":{"id":"2a664f564d4ae9b9","repo":"Hmbown/CodeWhale","slug":"operation-key-cannot-contain-leading-or-trailing-whitespace","errorCode":null,"errorMessage":"operation_key cannot contain leading or trailing whitespace","messagePattern":"operation_key cannot contain leading or trailing whitespace","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_threads.rs","lineNumber":3505,"sourceCode":"#[derive(Debug, thiserror::Error)]\npub(crate) enum RuntimeTurnOperationLookupError {\n    #[error(\"Invalid thread id or operation key\")]\n    InvalidRequest,\n    #[error(\"Turn operation acceptance is incomplete; retry lookup\")]\n    Incomplete,\n    #[error(\"Turn operation lookup unavailable\")]\n    Unavailable,\n}\n\nfn validate_runtime_turn_operation_key(value: &str) -> Result<()> {\n    if value.is_empty() {\n        bail!(\"operation_key cannot be empty\");\n    }\n    if value.len() > MAX_RUNTIME_TURN_OPERATION_KEY_BYTES {\n        bail!(\"operation_key cannot exceed {MAX_RUNTIME_TURN_OPERATION_KEY_BYTES} UTF-8 bytes\");\n    }\n    if value.trim() != value {\n        bail!(\"operation_key cannot contain leading or trailing whitespace\");\n    }\n    if value.chars().any(char::is_control) {\n        bail!(\"operation_key cannot contain control characters\");\n    }\n    Ok(())\n}\n\nfn validate_sha256_fingerprint(value: &str, label: &str) -> Result<()> {\n    if value.len() != 64 || !value.bytes().all(|byte| byte.is_ascii_hexdigit()) {\n        bail!(\"{label} must be a SHA-256 hex digest\");\n    }\n    Ok(())\n}\n\nfn runtime_turn_operation_key_fingerprint(\n    owner_id: &str,\n    thread_id: &str,\n    operation_key: &str,","sourceCodeStart":3487,"sourceCodeEnd":3523,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_threads.rs#L3487-L3523","documentation":"validate_runtime_turn_operation_key rejects operation keys with leading or trailing whitespace (value.trim() != value). Keys are used as canonical identifiers and fingerprint inputs, so untrimmed values would create divergent identities for the same logical operation.","triggerScenarios":"Passing an operation_key that begins or ends with space/tab/newline — commonly from user-supplied config values, CLI args pasted with trailing spaces, or string templates that append a newline.","commonSituations":"Reading a key from a config file or env var without trimming; format! templates ending in '\\n'; copy-pasted keys with a trailing space.","solutions":["Call .trim() on the key before passing it","Fix the source (config line, env var, template) that introduces the whitespace","Add a trim+assert step in your key-construction helper"],"exampleFix":"// before\nlet key = env::var(\"CODEWHALE_OP_KEY\")?;\n// after\nlet key = env::var(\"CODEWHALE_OP_KEY\")?.trim().to_string();","handlingStrategy":"validation","validationCode":"let key = candidate.trim();\nassert_eq!(key, candidate, \"operation_key must not have surrounding whitespace\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Trim any key read from config/env/CLI","Avoid templates that append trailing newlines","Canonicalize keys in a single helper used everywhere"],"tags":["validation","whitespace","runtime"],"backgroundTag":"invalid-argument-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}