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
- Read the wrapped serde error (available via the error chain) to identify the offending property.
- Fix option names and value types to match ClickHouseConfig's expected fields.
- Remove unknown/legacy properties and re-create the sink.
- 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
- Validate property names/types against ClickHouseConfig before submitting DDL.
- Inspect the wrapped serde error chain for the exact offending field.
- Remove unknown or legacy properties.
- Keep a canonical property list per connector in deployment tooling.
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.