risingwavelabs/risingwave · error · SinkError::Config

serde_json deserialization error of ClickHouseConfig from pr

Error message

serde_json deserialization error of ClickHouseConfig from properties (wrapped error)

What it means

ClickHouseConfig::from_btreemap serializes the user's WITH properties into JSON and deserializes them into ClickHouseConfig. If serde cannot deserialize the value (missing/wrongly-typed fields), the underlying serde error is wrapped in a SinkError::Config with this message.

Source

Thrown at src/connector/src/sink/clickhouse.rs:383

    is_append_only: bool,
}

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

impl ClickHouseConfig {
    pub fn from_btreemap(properties: BTreeMap<String, String>) -> Result<Self> {
        let config =
            serde_json::from_value::<ClickHouseConfig>(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)
    }
}

impl TryFrom<SinkParam> for ClickHouseSink {
    type Error = SinkError;

    fn try_from(param: SinkParam) -> std::result::Result<Self, Self::Error> {
        let schema = param.schema();
        let pk_indices = param.downstream_pk_or_empty();

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Read the wrapped serde error (available via the error chain) to identify the offending property.
  2. Fix option names and value types to match ClickHouseConfig's expected fields.
  3. Remove unknown/legacy properties and re-create the sink.
  4. Validate the full property set against the ClickHouse sink documentation before submitting.

Example fix

// before
WITH (connector='clickhouse', type='append only', url='...', ...)
// after
WITH (connector='clickhouse', type='append-only', url='http://...', table='t', ...)
Defensive patterns

Strategy: try-catch

Validate before calling

function validateClickHouseProps(props) {
  const required = ['type', 'url', 'table'];
  for (const k of required) if (!(k in props)) throw new Error(`Missing ClickHouse sink property: ${k}`);
  if (!['append-only', 'upsert'].includes(props.type)) throw new Error(`Invalid type: ${props.type}`);
}

Try / catch

try {
  await createSink({ connector: 'clickhouse', ...props });
} catch (e) {
  if (String(e.message).includes('serde_json deserialization error of ClickHouseConfig')) {
    // inspect e.cause / error chain for the serde field error and fix properties
  } else throw e;
}

Prevention

When it happens

Trigger: CREATE SINK ... WITH (connector='clickhouse', ...) where a property has an unexpected name or type, or serde_json conversion of the BTreeMap fails (e.g. non-string-derived values that violate the expected schema).

Common situations: Misspelled option names, wrong value types (e.g. numeric strings where bool/number expected), or unknown fields that serde's config struct rejects.

Related errors


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