risingwavelabs/risingwave · error · SinkError::Config
{serde_json URL parse error for RedisCommon}
Error message
{serde_json URL parse error for RedisCommon} What it means
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.
Source
Thrown at src/connector/src/sink/redis.rs:195
RedisSinkPayloadWriterInput::RedisGeoKey((key, member)) => {
pipe.zrem(key, member);
}
_ => return Err(SinkError::Redis("RedisPipe del not match".to_owned())),
},
};
Ok(())
}
}
pub enum RedisConn {
// Redis deployed as a cluster, clusters with only one node should also use this conn
Cluster(ClusterConnection),
// Redis is not deployed as a cluster
Single(MultiplexedConnection),
}
impl RedisCommon {
pub async fn build_conn_and_pipe(&self) -> ConnectorResult<(RedisConn, RedisPipe)> {
match serde_json::from_str(&self.url).map_err(|e| SinkError::Config(anyhow!(e))) {
Ok(v) => {
if let Value::Array(list) = v {
let list = list
.into_iter()
.map(|s| {
if let Value::String(s) = s {
Ok(s)
} else {
Err(SinkError::Redis(
"redis.url must be array of string".to_owned(),
)
.into())
}
})
.collect::<ConnectorResult<Vec<String>>>()?;
let client = ClusterClient::new(list)?;
Ok((View on GitHub (pinned to 6469eb736d)
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.
Example fix
// before url = 'redis://127.0.0.1:6379' // after url = '"redis://127.0.0.1:6379"'
Defensive patterns
Strategy: validation
Validate before calling
// Validate the url option is valid JSON before creating the sink
fn validate_redis_url(url: &str) -> Result<(), serde_json::Error> {
serde_json::from_str::<serde_json::Value>(url).map(|_| ())
} Type guard
fn is_json_string_or_string_array(s: &str) -> bool {
serde_json::from_str::<serde_json::Value>(s)
.map(|v| v.is_string() || matches!(&v, serde_json::Value::Array(a) if a.iter().all(|x| x.is_string())))
.unwrap_or(false)
} Try / catch
match RedisCommon::build_conn_and_pipe(&common).await {
Err(SinkError::Config(e)) => eprintln!("invalid redis url JSON: {e:#}"),
Err(e) => return Err(e),
Ok((conn, pipe)) => { /* proceed */ }
} Prevention
- 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
When it happens
Trigger: 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].
Common situations: 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.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- {serde_json deserialization error for RedisConfig from prope
- {serde_json deserialization error for PulsarConfig from prop
- Redis Sink Primary Key must be specified.
- missing FORMAT ... ENCODE ...
- SinkError::Config(anyhow!(e))
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/815520029d4fc77f.
Report an issue: GitHub.