{"record":{"id":"f4ba23b14b4a945d","repo":"risingwavelabs/risingwave","slug":"http-sink-payload-column-must-be-varchar-or-jsonb","errorCode":null,"errorMessage":"HTTP sink payload column must be varchar or jsonb, got {:?}","messagePattern":"HTTP sink payload column must be varchar or jsonb, got (.+?)","errorType":"validation","errorClass":"SinkError::Config","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/http.rs","lineNumber":193,"sourceCode":"                    return Err(SinkError::Config(anyhow!(\n                        \"HTTP sink url column must be varchar, got {:?}\",\n                        fields[url_index].data_type\n                    )));\n                }\n                HttpUrl::Dynamic { url_index }\n            }\n            (None, None) => {\n                return Err(SinkError::Config(anyhow!(\n                    \"HTTP sink requires either url option or url column\"\n                )));\n            }\n        };\n\n        (payload_index, url, fields[payload_index].data_type.clone())\n    };\n\n    if payload_type != DataType::Varchar && payload_type != DataType::Jsonb {\n        return Err(SinkError::Config(anyhow!(\n            \"HTTP sink payload column must be varchar or jsonb, got {:?}\",\n            payload_type\n        )));\n    }\n\n    let mut header_map = HeaderMap::new();\n    header_map.insert(\n        CONTENT_TYPE,\n        content_type\n            .unwrap_or(match payload_type {\n                DataType::Varchar => \"text/plain\",\n                DataType::Jsonb => \"application/json\",\n                _ => unreachable!(\"validated HTTP sink column type\"),\n            })\n            .parse()\n            .context(\"invalid content_type\")\n            .map_err(SinkError::Config)?,\n    );","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/http.rs#L175-L211","documentation":"The HTTP sink sends the `payload` column as the request body, so it must be a string (VARCHAR) or JSONB that can be serialized. `validate_http_sink` rejects the sink if the payload column has any other type (e.g. INT, struct, bytea).","triggerScenarios":"Creating an HTTP sink whose `payload` column (located by name at `payload_index`) is typed as anything other than VARCHAR or JSONB — checked in `try_from` -> `validate_http_sink` after URL resolution.","commonSituations":"Payload column typed as INT/BYTEA/struct in the table; users expecting the sink to stringify arbitrary types; schema drift after ALTER TABLE changes the payload column type.","solutions":["Cast the payload column in the sink query: SELECT payload::JSONB AS payload ... or payload::VARCHAR","Change the underlying table column type to VARCHAR or JSONB","Serialize complex types to JSONB before sinking"],"exampleFix":"// before\nSELECT payload FROM t; -- payload is INT\n// after\nSELECT payload::VARCHAR AS payload FROM t; -- or payload::JSONB","handlingStrategy":"validation","validationCode":"if let Some(f) = fields.iter().find(|f| f.name == \"payload\") {\n    let ok = f.data_type == DataType::Varchar || f.data_type == DataType::Jsonb;\n    assert!(ok, \"payload column must be VARCHAR or JSONB, got {:?}\", f.data_type);\n}","typeGuard":"fn is_valid_payload(f: &Field) -> bool {\n    matches!(f.data_type, DataType::Varchar | DataType::Jsonb)\n}","tryCatchPattern":null,"preventionTips":["Store HTTP payloads as VARCHAR or JSONB only","Cast other types (e.g. ::JSONB for structs) in the sink SELECT","Watch for ALTER TABLE changes to the payload column type"],"tags":["sink","http","type-mismatch","risingwave"],"backgroundTag":"type-mismatch","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}