{"record":{"id":"c26c8d7cccb8fd1e","repo":"risingwavelabs/risingwave","slug":"dynamic-serde-deserialization-error-from-sink-pr","errorCode":null,"errorMessage":"(dynamic: serde deserialization error from sink properties)","messagePattern":"\\(dynamic: serde deserialization error from sink properties\\)","errorType":"validation","errorClass":"SinkError::Config","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/snowflake_redshift/snowflake.rs","lineNumber":233,"sourceCode":"                if let Some(pwd) = self.private_key_file_pwd.clone() {\n                    connection_properties.push((\"private_key_file_pwd\".to_owned(), pwd));\n                }\n            }\n            _ => {\n                // This should never happen since from_btreemap validates auth_method\n                unreachable!(\n                    \"Invalid auth_method - should have been caught during config validation\"\n                )\n            }\n        }\n\n        Ok((jdbc_url, connection_properties))\n    }\n\n    pub fn from_btreemap(properties: &BTreeMap<String, String>) -> Result<Self> {\n        let mut config =\n            serde_json::from_value::<SnowflakeV2Config>(serde_json::to_value(properties).unwrap())\n                .map_err(|e| SinkError::Config(anyhow!(e)))?;\n        if config.r#type != SINK_TYPE_APPEND_ONLY && config.r#type != SINK_TYPE_UPSERT {\n            return Err(SinkError::Config(anyhow!(\n                \"`{}` must be {}, or {}\",\n                SINK_TYPE_OPTION,\n                SINK_TYPE_APPEND_ONLY,\n                SINK_TYPE_UPSERT\n            )));\n        }\n        if config.r#type == SINK_TYPE_UPSERT && !config.with_s3 {\n            return Err(SinkError::Config(anyhow!(\n                \"Snowflake upsert sinks require `with_s3 = true` so all CDC rows are loaded by the serialized COPY INTO task\"\n            )));\n        }\n        let has_upsert_task_config = config.snowflake_cdc_table_name.is_some()\n            || properties.contains_key(\"write.target.interval.seconds\")\n            || config.snowflake_warehouse.is_some()\n            || config.task_serverless\n            || config.task_target_completion_interval.is_some();","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/snowflake_redshift/snowflake.rs#L215-L251","documentation":"`from_btreemap` deserializes the sink's WITH properties into `SnowflakeV2Config` via serde. Any unknown, mistyped, or missing option fails serde deserialization, and the error is wrapped in a generic SinkError::Config with the serde message. It is the entry-point validation for all Snowflake sink properties, so most misconfigurations surface here.","triggerScenarios":"Creating a Snowflake sink whose properties fail `serde_json::from_value::<SnowflakeV2Config>`, e.g. unknown key `jdbc_url` instead of `jdbc.url`, wrong value type for `s3.bucket_name`, or a missing required field like `snowflake.schema.name`.","commonSituations":"Typos in WITH option names; using deprecated option names after connector upgrades; passing non-string/incorrectly-typed values; forgetting required Snowflake object identifiers.","solutions":["Read the serde error message appended by this error: it names the offending field/reason.","Fix the WITH option names and values to match `SnowflakeV2Config` (e.g. `jdbc.url`, `snowflake.schema.name`).","Diff against the documented Snowflake sink options for your RisingWave version, since options evolve between releases.","Validate the properties map offline with `SnowflakeV2SinkConfig::from_btreemap` before creating the sink."],"exampleFix":"// before\nWITH (connector='snowflake', jdbc_url='jdbc:snowflake://...');\n// after\nWITH (connector='snowflake', snowflake.jdbc.url='jdbc:snowflake://...');","handlingStrategy":"validation","validationCode":"match SnowflakeV2SinkConfig::from_btreemap(&props) {\n    Ok(cfg) => println!(\"config ok: {:?}\", cfg),\n    Err(e) => eprintln!(\"bad snowflake sink config: {e}\"),\n}","typeGuard":null,"tryCatchPattern":"// Catch and surface the serde detail\nmatch result {\n    Err(SinkError::Config(msg)) => log::error!(\"snowflake sink config rejected: {msg}\"),\n    Err(e) => return Err(e),\n    Ok(cfg) => proceed(cfg),\n}","preventionTips":["Read the wrapped serde message; it names the exact bad field.","Diff options against the connector docs for your RisingWave version.","Test property maps in a unit test with from_btreemap."],"tags":["rust","snowflake","serde","sink-config"],"backgroundTag":"schema-validation-failed","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}