risingwavelabs/risingwave · error · SinkError::Config

HTTP sink method must be POST or PUT, got '{method}'

Error message

HTTP sink method must be POST or PUT, got '{method}'

What it means

Validation guard in validate_http_sink (called via try_from) that normalizes the user-supplied `method` option: only POST and PUT are accepted; any other value (e.g. GET, DELETE, or a misspelled method) is rejected before a reqwest::Method is constructed. The message interpolates the offending method string.

Source

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

    schema: &Schema,
    url: Option<&str>,
    method: Option<&str>,
    content_type: Option<&str>,
    headers: &BTreeMap<String, String>,
    unknown_fields: std::collections::HashMap<String, String>,
) -> Result<HttpSink> {
    if !is_append_only && !ignore_delete {
        return Err(SinkError::Config(anyhow!(
            "HTTP sink only supports append-only mode"
        )));
    }

    let method = match method {
        None => reqwest::Method::POST,
        Some(method) if method.eq_ignore_ascii_case("POST") => reqwest::Method::POST,
        Some(method) if method.eq_ignore_ascii_case("PUT") => reqwest::Method::PUT,
        Some(method) => {
            return Err(SinkError::Config(anyhow!(
                "HTTP sink method must be POST or PUT, got '{method}'"
            )));
        }
    };

    let fields = schema.fields();
    let (payload_index, url, payload_type) = if fields.len() == 1 {
        let Some(url) = url else {
            return Err(SinkError::Config(anyhow!(
                "HTTP sink requires url option when schema has exactly 1 column"
            )));
        };
        let url = url
            .parse()
            .context("invalid URL")
            .map_err(SinkError::Config)?;
        (0, HttpUrl::Static(url), fields[0].data_type.clone())
    } else {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Set method='POST' (default) or method='PUT' in the WITH options
  2. Remove the method option to accept the POST default
  3. Use a different delivery mechanism if you need other verbs

Example fix

// before
WITH (connector='http', url='...', method='PATCH')
// after
WITH (connector='http', url='...', method='POST')
Defensive patterns

Strategy: validation

Validate before calling

if let Some(m) = options.get("method") {
    let ok = m.eq_ignore_ascii_case("POST") || m.eq_ignore_ascii_case("PUT");
    if !ok { return Err(format!("method must be POST or PUT, got '{m}'")); }
}

Try / catch

match sink::try_create(props) {
    Err(e) if e.to_string().contains("method must be POST or PUT") => {
        log::error!("fix the method option: {e}");
    }
    r => r?,
}

Prevention

When it happens

Trigger: `validate_http_sink` receives method=Some(m) where m is not 'POST' or 'PUT' (case-insensitive).

Common situations: User sets method='GET' hoping to trigger webhooks via query; copy-pasting method options from other sinks; typo like 'PosT' is fine, but 'PATCH'/'DELETE' are not.

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


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