risingwavelabs/risingwave · error · SinkError::Config

{e}

Error message

{e}

What it means

This wraps a serde deserialization failure when converting the remaining sink options into an `HttpConfig` via `serde_json::from_value`. A provided option has a wrong name or type for HttpConfig, so deserialization fails.

Source

Thrown at src/connector/src/sink/http.rs:77

impl EnforceSecret for HttpConfig {}

impl HttpConfig {
    pub fn from_btreemap(
        values: BTreeMap<String, String>,
    ) -> Result<(Self, BTreeMap<String, String>)> {
        // Extract header.* keys before serde parsing
        let mut headers = BTreeMap::new();
        let mut rest = BTreeMap::new();
        for (k, v) in &values {
            if let Some(header_name) = k.strip_prefix("header.") {
                headers.insert(header_name.to_owned(), v.clone());
            } else {
                rest.insert(k.clone(), v.clone());
            }
        }

        let config = serde_json::from_value::<HttpConfig>(serde_json::to_value(rest).unwrap())
            .map_err(|e| SinkError::Config(anyhow!(e)))?;

        if config.r#type != SINK_TYPE_APPEND_ONLY {
            return Err(SinkError::Config(anyhow!(
                "HTTP sink only supports append-only mode"
            )));
        }

        Ok((config, headers))
    }
}

#[derive(Clone, Debug)]
enum HttpUrl {
    Static(reqwest::Url),
    Dynamic { url_index: usize },
}

/// Validates the HTTP sink parameters and returns the sink so callers can use it directly without

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check each WITH option against HttpConfig's supported fields and fix typos
  2. Ensure value types match the struct fields (string vs bool vs number)
  3. Remove unsupported/legacy options from the WITH clause
  4. Enable serde deny_unknown_fields awareness — consult docs for accepted options

Example fix

// before
CREATE SINK s FROM mv WITH (connector='http', url='...', method='POST', unknowOpt='x');
// after
CREATE SINK s FROM mv WITH (connector='http', url='...', method='POST');
Defensive patterns

Strategy: validation

Validate before calling

// lint your WITH options against HttpConfig fields before creating the sink
let allowed = ["connector", "url", "method", "type", "headers"];
let unknown: Vec<_> = options.keys().filter(|k| !allowed.contains(&k.as_str())).collect();
if !unknown.is_empty() { return Err(format!("unknown http sink options: {unknown:?}")); }

Try / catch

match HttpSink::from_btreemap(&props, ...) {
    Err(SinkError::Config(e)) => log::error!("bad HTTP sink config: {e:#}"),
    ok => ok?,
}

Prevention

When it happens

Trigger: Calling `from_btreemap` with user-provided sink options (with known keys like url/method/headers removed into `rest`) that contain an unknown field or wrong-typed value for HttpConfig.

Common situations: Typo in a sink option key (e.g. 'conector' instead of 'connector'); passing a string where a number/bool is expected; extra legacy options not recognized by HttpConfig's serde definition.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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