{"record":{"id":"f11c185b04f263d4","repo":"risingwavelabs/risingwave","slug":"invalid-utf-8-in-key-header","errorCode":null,"errorMessage":"invalid UTF-8 in `{key}` header","messagePattern":"invalid UTF-8 in `(.+?)` header","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"src/frontend/src/webhook/payload.rs","lineNumber":191,"sourceCode":"fn parse_bool_header(headers: &HeaderMap, key: &'static str) -> Result<Option<bool>> {\n    match header_value(headers, key)?.as_deref() {\n        Some(\"true\") => Ok(Some(true)),\n        Some(\"false\") => Ok(Some(false)),\n        Some(value) => Err(err(\n            anyhow!(\"unrecognized value `{value}` for `{key}`\"),\n            StatusCode::BAD_REQUEST,\n        )),\n        None => Ok(None),\n    }\n}\n\nfn header_value(headers: &HeaderMap, key: &'static str) -> Result<Option<String>> {\n    headers\n        .get(key)\n        .map(|value| {\n            value.to_str().map(|value| value.to_owned()).map_err(|e| {\n                err(\n                    anyhow!(e).context(format!(\"invalid UTF-8 in `{key}` header\")),\n                    StatusCode::BAD_REQUEST,\n                )\n            })\n        })\n        .transpose()\n}\n\n#[cfg(test)]\nmod tests {\n    use axum::http::{HeaderMap, HeaderValue};\n    use risingwave_common::row::{OwnedRow, Row};\n    use risingwave_common::types::{DataType, ScalarImpl, ToOwnedDatum};\n\n    use super::*;\n\n    fn decode_payload_row(columns: &[WebhookTableColumnDesc], payload: &[u8]) -> Result<OwnedRow> {\n        let mut access_builder = build_json_access_builder(&HeaderMap::new())?;\n        owned_row_from_payload_row(&mut access_builder, columns, payload)","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/frontend/src/webhook/payload.rs#L173-L209","documentation":"HTTP header values are not guaranteed to be UTF-8 (they are arbitrary bytes per the HTTP spec). When a webhook connector header cannot be converted with HeaderValue::to_str(), RisingWave wraps the conversion error with this context and returns 400 BAD_REQUEST. It guarantees all header-derived configuration strings are valid Rust strings.","triggerScenarios":"Sending any webhook connector header (timestamp handling, timestamptz handling, time handling, bigint handling, boolean flags) containing non-ASCII or raw non-UTF-8 bytes, e.g. values with curly quotes, BOM, or binary garbage.","commonSituations":"Proxies or clients mangling header encodings, copy-pasted values containing smart quotes or zero-width characters, scripts writing latin-1 encoded headers.","solutions":["Inspect and re-send the offending header with plain ASCII/UTF-8 content.","Strip or replace non-ASCII characters from the value on the client side.","Check intermediate proxies/CDNs that may re-encode headers.","Avoid copy-pasting from rich-text editors that insert smart quotes."],"exampleFix":"// before\nheaders.insert(\"x-rw-timestamp-handling\", “utc”.parse().unwrap()); // smart quotes\n// after\nheaders.insert(\"x-rw-timestamp-handling\", \"utc\".parse().unwrap());","handlingStrategy":"validation","validationCode":"for (const [k, v] of Object.entries(headers)) {\n  if (!/^\\x20-\\x7e*$/.test(v)) throw new Error(`header ${k} contains non-ASCII characters: ${JSON.stringify(v)}`);\n}","typeGuard":null,"tryCatchPattern":"// Rust\nmatch response_or_result {\n    Err(e) if e.to_string().contains(\"invalid UTF-8\") => {\n        // sanitize the offending header and retry once\n    }\n    other => other?,\n}","preventionTips":["Restrict header values to printable ASCII when building webhook requests.","Avoid copy-pasting config from rich-text editors (smart quotes, zero-width chars).","Set explicit charset/encoding in scripts writing headers (e.g. latin-1 vs utf-8 pitfalls)."],"tags":["http","headers","encoding","utf8"],"backgroundTag":"invalid-argument-format","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}