risingwavelabs/risingwave · error · SinkError::Config
{serde_json deserialization error for PostgresConfig from…
Error message
{serde_json deserialization error for PostgresConfig from properties} What it means
`PostgresConfig::from_btreemap` deserializes the WITH options map into `PostgresConfig` via serde_json and wraps any deserialization failure as `SinkError::Config`. This generic message covers mistyped, missing, or unknown Postgres sink option fields.
Solutions
- Check the serde detail in the error output — it names the offending field
- Verify required options: host, port, database, schema, table, username, password, and `type`
- Fix option names and value types to match PostgresConfig's expected fields
- Validate by re-running CREATE SINK after corrections
Example fix
// before WITH (connector='postgres', host='pg', port='5432', tablename='t', type='upsert'); // after WITH (connector='postgres', host='pg', port='5432', database='db', schema='public', table='t', user='u', password='p', type='upsert');
Defensive patterns
Strategy: validation
Validate before calling
let required = ["host", "port", "database", "schema", "table", "username", "password", "type"];
for k in required { assert!(options.contains_key(k), "missing postgres option: {}", k); }
assert!(options["port"].parse::<u16>().is_ok(), "port must be numeric");
assert!(matches!(options["type"].as_str(), "append-only" | "upsert")); Try / catch
match PostgresConfig::from_btreemap(opts.clone()) {
Ok(cfg) => cfg,
Err(SinkError::Config(e)) => return Err(format!("bad postgres options: {e}")),
Err(e) => return Err(format!("postgres sink error: {e}")),
} Prevention
- Verify every documented option name before running CREATE SINK
- Keep port as a plain integer string
- Quote option values containing spaces or special characters
When it happens
Trigger: Calling `PostgresConfig::from_btreemap(properties)` when the options map cannot be deserialized: missing required fields (host, port, database, table, `type`), wrong-typed values (e.g. non-numeric port), or unknown keys (when strict deserialization applies).
Common situations: Typos in option names (`tablename` vs `table`); missing `type` option; passing the connection string in the wrong field; quoting problems in CREATE SINK options.
Related errors
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/a56c12d3ef902482.
Report an issue: GitHub.
Appendix: source
Thrown at src/connector/src/sink/postgres.rs:154
.context("failed to check foreign key constraints")?
.get::<_, bool>(0);
if has_foreign_key {
return Err(SinkError::Config(anyhow!(
"Postgres sink does not support target table \"{}\".\"{}\" with foreign key constraints. Please remove foreign key constraints from the target table or choose a different sink table.",
schema,
table,
)));
}
Ok(())
}
impl PostgresConfig {
pub fn from_btreemap(properties: BTreeMap<String, String>) -> Result<Self> {
let config =
serde_json::from_value::<PostgresConfig>(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 pg_connection_config(&self) -> PgConnectionConfig {
PgConnectionConfig {
host: self.host.clone(),
port: self.port,
user: self.user.clone(),
password: self.password.clone(),
database: self.database.clone(),View on GitHub (pinned to 6469eb736d)