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.

Solutions

  1. Wrap the URL in quotes so it is valid JSON: "redis://127.0.0.1:6379".
  2. If multiple URLs are supported, pass a JSON array of quoted strings: ["redis://host1:6379","redis://host2:6379"].
  3. Validate the url value with serde_json::from_str before creating the sink.
  4. 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

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.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/815520029d4fc77f. Report an issue: GitHub.

Appendix: 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)