{"record":{"id":"2375091f5526b817","repo":"risingwavelabs/risingwave","slug":"serde-json-deserialization-error-for-redisconfig","errorCode":null,"errorMessage":"{serde_json deserialization error for RedisConfig from properties}","messagePattern":"\\{serde_json deserialization error for RedisConfig from properties\\}","errorType":"validation","errorClass":"SinkError::Config","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/redis.rs","lineNumber":257,"sourceCode":"    pub unknown_fields: std::collections::HashMap<String, String>,\n}\n\ncrate::impl_sink_unknown_fields!(RedisConfig);\n\nimpl EnforceSecret for RedisConfig {\n    fn enforce_secret<'a>(prop_iter: impl Iterator<Item = &'a str>) -> ConnectorResult<()> {\n        for prop in prop_iter {\n            RedisCommon::enforce_one(prop)?;\n        }\n        Ok(())\n    }\n}\n\nimpl RedisConfig {\n    pub fn from_btreemap(properties: BTreeMap<String, String>) -> Result<Self> {\n        let config =\n            serde_json::from_value::<RedisConfig>(serde_json::to_value(properties).unwrap())\n                .map_err(|e| SinkError::Config(anyhow!(e)))?;\n        Ok(config)\n    }\n}\n\n#[derive(Debug)]\npub struct RedisSink {\n    config: RedisConfig,\n    schema: Schema,\n    pk_indices: Vec<usize>,\n    format_desc: SinkFormatDesc,\n    db_name: String,\n    sink_from_name: String,\n}\n\nimpl EnforceSecret for RedisSink {\n    fn enforce_secret<'a>(prop_iter: impl Iterator<Item = &'a str>) -> ConnectorResult<()> {\n        for prop in prop_iter {\n            RedisConfig::enforce_one(prop)?;","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/redis.rs#L239-L275","documentation":"RedisConfig::from_btreemap converts the sink's WITH-clause properties (BTreeMap<String, String>) to a JSON value and deserializes it into RedisConfig; any serde failure becomes SinkError::Config. The library throws it because the Redis sink cannot start without a structurally valid configuration (url(s) and other required fields).","triggerScenarios":"Creating a Redis sink whose properties lack required RedisConfig fields (e.g. url), or supply values that fail JSON deserialization (wrong types, empty strings where structure is expected, invalid nested values).","commonSituations":"Missing `url` option in CREATE SINK WITH; typo'd option names so required fields deserialize as null; Redis cluster mode options changed between RisingWave versions; extra unrelated options tripping strict deserialization.","solutions":["Ensure the required `url` field (JSON-encoded string or array of strings) is present in WITH options.","Fix the field name/type referenced by the serde error message in the returned anyhow text.","Remove unknown or stale WITH options not recognized by RedisConfig.","Test the properties map against RedisConfig::from_btreemap locally to see the precise serde failure.","Consult the RisingWave Redis sink docs for the current option set."],"exampleFix":"// before\nCREATE SINK s FROM mv WITH (connector = 'redis');\n// after\nCREATE SINK s FROM mv WITH (connector = 'redis', url = '\"redis://127.0.0.1:6379\"') FORMAT APPEND ONLY ENCODE JSON;","handlingStrategy":"validation","validationCode":"// Ensure required redis sink options exist before constructing RedisConfig\nfn validate_redis_props(props: &BTreeMap<String, String>) -> Result<(), String> {\n    if !props.contains_key(\"url\") { return Err(\"missing required redis sink option: url\".into()); }\n    Ok(())\n}","typeGuard":"fn has_url(props: &BTreeMap<String, String>) -> bool {\n    props.get(\"url\").map_or(false, |u| !u.trim().is_empty())\n}","tryCatchPattern":"match RedisConfig::from_btreemap(props) {\n    Ok(cfg) => { /* proceed */ }\n    Err(SinkError::Config(e)) => log::error!(\"invalid redis sink properties: {e:#}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Always provide the `url` WITH option","Keep option names aligned with RedisConfig fields","Drop unknown/stale options from DDL templates","Validate against docs for your RisingWave version"],"tags":["rust","serde","redis","sink","config"],"backgroundTag":"missing-required-config-field","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"}