risingwavelabs/risingwave · error · SinkError::Config
`{}` must be {}, or {}
Error message
`{}` must be {}, or {} What it means
Required-option guard in SqlServerConfig::from_btreemap: an enumerated with-clause option (such as the sink `type`) was set to a value outside the allowed alternatives; the message lists the accepted values. Fires when the property passes serde but fails the explicit value check.
Source
Thrown at src/connector/src/sink/sqlserver.rs:88
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! {
"sqlserver.password"
};View on GitHub (pinned to 6469eb736d)
Solutions
- Set the `type` option to exactly 'append_only' or 'upsert' in the sink WITH clause
- Check for typos/extra whitespace/case mismatch in the value
- Review the SQL Server sink documentation for the accepted sink types
Example fix
// before WITH ( 'type' = 'append-only' ) // after WITH ( 'type' = 'append_only' )
Defensive patterns
Strategy: validation
Validate before calling
fn check_sink_type(props: &BTreeMap<String, String>) -> Result<(), String> {
match props.get("type").map(String::as_str) {
Some("append_only") | Some("upsert") => Ok(()),
Some(other) => Err(format!("type must be append_only or upsert, got {}", other)),
None => Ok(()),
}
} Type guard
fn is_valid_sink_type(s: &str) -> bool { s == "append_only" || s == "upsert" } Try / catch
match create_sink(cfg) {
Err(e) if e.to_string().contains("must be append_only, or upsert") => fix_and_retry_with_valid_sink_type(),
other => other,
} Prevention
- Always use the exact literals 'append_only' / 'upsert' (underscores)
- Lint sink WITH clauses for known option values
- Reuse shared constants rather than hand-typed strings
When it happens
Trigger: Creating a SQL Server sink with WITH option `type` set to anything other than SINK_TYPE_APPEND_ONLY ('append_only') or SINK_TYPE_UPSERT ('upsert').
Common situations: Typo like 'append-only' or 'upsert_only', copying `type='debezium'` or other sink-type values from a different connector's config.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- sink format unsupported: {}
- sink encode unsupported: {}
- unsupported {} as sink key encode
- {e}
- Primary key not defined for upsert SQL Server sink (please d
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/39292ba128d95687.
Report an issue: GitHub.