risingwavelabs/risingwave · error · SinkError::Config

{e}

Error message

{e}

What it means

SqlServerConfig::from_btreemap deserializes the user-supplied property map into the SqlServerConfig struct via serde_json. If any property fails to deserialize (wrong type, unknown/misspelled field, malformed value), the serde error is wrapped as SinkError::Config.

Source

Thrown at src/connector/src/sink/sqlserver.rs:86

    #[serde_as(as = "DisplayFromStr")]
    pub max_batch_rows: usize,
    pub r#type: String, // accept "append-only" or "upsert"

    #[serde(flatten)]
    pub unknown_fields: std::collections::HashMap<String, String>,
}

crate::impl_sink_unknown_fields!(SqlServerConfig);

pub fn sql_server_default_schema() -> String {
    "dbo".to_owned()
}

impl SqlServerConfig {
    pub fn from_btreemap(properties: BTreeMap<String, String>) -> Result<Self> {
        let config =
            serde_json::from_value::<SqlServerConfig>(serde_json::to_value(properties).unwrap())
                .map_err(|e| SinkError::Config(anyhow!(e)))?;
        if config.r#type != SINK_TYPE_APPEND_ONLY && config.r#type != SINK_TYPE_UPSERT {
            return Err(SinkError::Config(anyhow!(
                "`{}` must be {}, or {}",
                SINK_TYPE_OPTION,
                SINK_TYPE_APPEND_ONLY,
                SINK_TYPE_UPSERT
            )));
        }
        Ok(config)
    }

    pub fn full_object_path(&self) -> String {
        format!("[{}].[{}].[{}]", self.database, self.schema, self.table)
    }
}

impl EnforceSecret for SqlServerConfig {
    const ENFORCE_SECRET_PROPERTIES: Set<&'static str> = phf_set! {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Read the serde error message in `e` — it names the offending field and expected type
  2. Fix the option name/value in the CREATE SINK ... WITH (...) clause to match SqlServerConfig fields
  3. Compare against the documented SQL Server sink options list and remove unrelated options

Example fix

// before
WITH ( 'max_batch_rows' = 'many' )
// after
WITH ( 'max_batch_rows' = '1000' )
Defensive patterns

Strategy: validation

Validate before calling

fn validate_sqlserver_props(props: &BTreeMap<String, String>) -> Result<(), String> {
    for k in props.keys() {
        if !KNOWN_SQLSERVER_OPTIONS.contains(&k.as_str()) { return Err(format!("unknown option: {}", k)); }
    }
    if let Some(v) = props.get("max_batch_rows") {
        v.parse::<usize>().map_err(|_| format!("max_batch_rows must be numeric, got {}", v))?;
    }
    Ok(())
}

Try / catch

match SqlServerConfig::from_btreemap(props) {
    Err(SinkError::Config(e)) => { log_config_error(&e); Err(e) }
    other => other,
}

Prevention

When it happens

Trigger: Calling SqlServerConfig::from_btreemap with properties whose keys/values do not match the serde expectations of SqlServerConfig, e.g. non-numeric max_batch_rows, unknown option names (without deny_unknown_fields leniency), or wrong types.

Common situations: Typos in sink WITH options, passing a string where a number is expected, copying options from another sink connector (e.g. Kafka-style options) into the SQL Server sink.

Related errors


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