risingwavelabs/risingwave · error · SinkError::Config

{serde_json deserialization error for RedisConfig from prope

Error message

{serde_json deserialization error for RedisConfig from properties}

What it means

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).

Source

Thrown at src/connector/src/sink/redis.rs:257

    pub unknown_fields: std::collections::HashMap<String, String>,
}

crate::impl_sink_unknown_fields!(RedisConfig);

impl EnforceSecret for RedisConfig {
    fn enforce_secret<'a>(prop_iter: impl Iterator<Item = &'a str>) -> ConnectorResult<()> {
        for prop in prop_iter {
            RedisCommon::enforce_one(prop)?;
        }
        Ok(())
    }
}

impl RedisConfig {
    pub fn from_btreemap(properties: BTreeMap<String, String>) -> Result<Self> {
        let config =
            serde_json::from_value::<RedisConfig>(serde_json::to_value(properties).unwrap())
                .map_err(|e| SinkError::Config(anyhow!(e)))?;
        Ok(config)
    }
}

#[derive(Debug)]
pub struct RedisSink {
    config: RedisConfig,
    schema: Schema,
    pk_indices: Vec<usize>,
    format_desc: SinkFormatDesc,
    db_name: String,
    sink_from_name: String,
}

impl EnforceSecret for RedisSink {
    fn enforce_secret<'a>(prop_iter: impl Iterator<Item = &'a str>) -> ConnectorResult<()> {
        for prop in prop_iter {
            RedisConfig::enforce_one(prop)?;

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Ensure the required `url` field (JSON-encoded string or array of strings) is present in WITH options.
  2. Fix the field name/type referenced by the serde error message in the returned anyhow text.
  3. Remove unknown or stale WITH options not recognized by RedisConfig.
  4. Test the properties map against RedisConfig::from_btreemap locally to see the precise serde failure.
  5. Consult the RisingWave Redis sink docs for the current option set.

Example fix

// before
CREATE SINK s FROM mv WITH (connector = 'redis');
// after
CREATE SINK s FROM mv WITH (connector = 'redis', url = '"redis://127.0.0.1:6379"') FORMAT APPEND ONLY ENCODE JSON;
Defensive patterns

Strategy: validation

Validate before calling

// Ensure required redis sink options exist before constructing RedisConfig
fn validate_redis_props(props: &BTreeMap<String, String>) -> Result<(), String> {
    if !props.contains_key("url") { return Err("missing required redis sink option: url".into()); }
    Ok(())
}

Type guard

fn has_url(props: &BTreeMap<String, String>) -> bool {
    props.get("url").map_or(false, |u| !u.trim().is_empty())
}

Try / catch

match RedisConfig::from_btreemap(props) {
    Ok(cfg) => { /* proceed */ }
    Err(SinkError::Config(e)) => log::error!("invalid redis sink properties: {e:#}"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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