{"record":{"id":"815520029d4fc77f","repo":"risingwavelabs/risingwave","slug":"serde-json-url-parse-error-for-rediscommon","errorCode":null,"errorMessage":"{serde_json URL parse error for RedisCommon}","messagePattern":"\\{serde_json URL parse error for RedisCommon\\}","errorType":"validation","errorClass":"SinkError::Config","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/redis.rs","lineNumber":195,"sourceCode":"                RedisSinkPayloadWriterInput::RedisGeoKey((key, member)) => {\n                    pipe.zrem(key, member);\n                }\n                _ => return Err(SinkError::Redis(\"RedisPipe del not match\".to_owned())),\n            },\n        };\n        Ok(())\n    }\n}\npub enum RedisConn {\n    // Redis deployed as a cluster, clusters with only one node should also use this conn\n    Cluster(ClusterConnection),\n    // Redis is not deployed as a cluster\n    Single(MultiplexedConnection),\n}\n\nimpl RedisCommon {\n    pub async fn build_conn_and_pipe(&self) -> ConnectorResult<(RedisConn, RedisPipe)> {\n        match serde_json::from_str(&self.url).map_err(|e| SinkError::Config(anyhow!(e))) {\n            Ok(v) => {\n                if let Value::Array(list) = v {\n                    let list = list\n                        .into_iter()\n                        .map(|s| {\n                            if let Value::String(s) = s {\n                                Ok(s)\n                            } else {\n                                Err(SinkError::Redis(\n                                    \"redis.url must be array of string\".to_owned(),\n                                )\n                                .into())\n                            }\n                        })\n                        .collect::<ConnectorResult<Vec<String>>>()?;\n\n                    let client = ClusterClient::new(list)?;\n                    Ok((","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/redis.rs#L177-L213","documentation":"RedisCommon::build_conn_and_pipe parses the sink's url field as JSON (either a single URL string or an array of URLs) with serde_json::from_str, mapping any parse failure to SinkError::Config. The library throws it because the URL(s) supplied in the sink options must be valid JSON strings to build Redis connections.","triggerScenarios":"Calling build_conn_and_pipe when RedisCommon.url is not valid JSON — e.g. a raw URL string 'redis://127.0.0.1:6379' without surrounding quotes, or a malformed array like [redis://a, redis://b].","commonSituations":"Users passing a plain Redis URL instead of a JSON-encoded string/array in WITH options; shell/SQL escaping stripping quotes; using a JSON array with non-string elements.","solutions":["Wrap the URL in quotes so it is valid JSON: \"redis://127.0.0.1:6379\".","If multiple URLs are supported, pass a JSON array of quoted strings: [\"redis://host1:6379\",\"redis://host2:6379\"].","Validate the url value with serde_json::from_str before creating the sink.","Check SQL escaping — inner double quotes may need to survive the WITH option parser."],"exampleFix":"// before\nurl = 'redis://127.0.0.1:6379'\n// after\nurl = '\"redis://127.0.0.1:6379\"'","handlingStrategy":"validation","validationCode":"// Validate the url option is valid JSON before creating the sink\nfn validate_redis_url(url: &str) -> Result<(), serde_json::Error> {\n    serde_json::from_str::<serde_json::Value>(url).map(|_| ())\n}","typeGuard":"fn is_json_string_or_string_array(s: &str) -> bool {\n    serde_json::from_str::<serde_json::Value>(s)\n        .map(|v| v.is_string() || matches!(&v, serde_json::Value::Array(a) if a.iter().all(|x| x.is_string())))\n        .unwrap_or(false)\n}","tryCatchPattern":"match RedisCommon::build_conn_and_pipe(&common).await {\n    Err(SinkError::Config(e)) => eprintln!(\"invalid redis url JSON: {e:#}\"),\n    Err(e) => return Err(e),\n    Ok((conn, pipe)) => { /* proceed */ }\n}","preventionTips":["Quote URLs so they are valid JSON strings","Use JSON arrays of quoted strings for multiple URLs","Beware SQL/shell escaping of double quotes","Test option parsing with serde_json::from_str first"],"tags":["rust","serde","redis","sink","json"],"backgroundTag":"json-parse-error","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"}