risingwavelabs/risingwave · warning

unsupported webhook payload format `{format}`

Error message

unsupported webhook payload format `{format}`

What it means

The `x-rw-webhook-format` header specified a payload format other than `plain` (case-insensitive). RisingWave webhooks currently only accept plain JSON payloads, so any other format value is rejected with HTTP 400 BAD_REQUEST before decoding starts.

Source

Thrown at src/frontend/src/webhook/payload.rs:82

                Err(error) if column.is_pk => Err(error),
                Err(_) => Ok(None),
            },
        )
        .collect::<AccessResult<Vec<_>>>()
        .map(OwnedRow::new);
    row.map_err(|e| {
        err(
            anyhow!(e).context("failed to decode webhook JSON payload"),
            StatusCode::UNPROCESSABLE_ENTITY,
        )
    })
}

fn json_properties_from_headers(headers: &HeaderMap) -> Result<JsonProperties> {
    let format = header_value(headers, WEBHOOK_FORMAT_HEADER)?.unwrap_or_else(|| "plain".into());
    if !format.eq_ignore_ascii_case("plain") {
        return Err(err(
            anyhow!("unsupported webhook payload format `{format}`"),
            StatusCode::BAD_REQUEST,
        ));
    }

    let encode = header_value(headers, WEBHOOK_ENCODE_HEADER)?.unwrap_or_else(|| "json".into());
    if !encode.eq_ignore_ascii_case("json") {
        return Err(err(
            anyhow!("unsupported webhook payload encoding `{encode}`"),
            StatusCode::BAD_REQUEST,
        ));
    }

    let timestamp_handling =
        parse_timestamp_handling(headers, WEBHOOK_JSON_TIMESTAMP_HANDLING_HEADER)?;
    let timestamptz_handling =
        parse_timestamptz_handling(headers, WEBHOOK_JSON_TIMESTAMPTZ_HANDLING_HEADER)?;
    let time_handling = parse_time_handling(headers, WEBHOOK_JSON_TIME_HANDLING_HEADER)?;
    let bigint_unsigned_handling =

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Remove the `x-rw-webhook-format` header entirely (defaults to `plain`).
  2. Set it explicitly to `plain` (case-insensitive).
  3. Send the body as raw plain JSON; use `x-rw-webhook-encode: json` for encoding, not format.
  4. If a non-JSON format is truly needed, transform it client-side before posting.
  5. Check release notes in case a newer RisingWave version adds formats.

Example fix

// before
curl -H 'x-rw-webhook-format: protobuf' -d @payload.bin $URL
// after
curl -H 'x-rw-webhook-encode: json' -H 'content-type: application/json' -d '{"a":1}' $URL
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_FORMATS = ['plain'];
const fmt = headers['x-rw-webhook-format'];
if (fmt && !SUPPORTED_FORMATS.includes(String(fmt).toLowerCase()))
  throw new Error(`unsupported webhook format: ${fmt} (only 'plain')`);

Type guard

const isSupportedFormat = (v) => typeof v === 'string' && v.toLowerCase() === 'plain';

Try / catch

if (!isSupportedFormat(headers['x-rw-webhook-format'] ?? 'plain'))
  throw new Error('unsupported webhook payload format');
const res = await fetch(url, { method: 'POST', headers, body });

Prevention

When it happens

Trigger: POST with header `x-rw-webhook-format: protobuf`, `csv`, or any value other than `plain` (any casing).

Common situations: Producers copy header templates from other systems expecting protobuf-encoded webhooks; a generic webhook sender adds a format header by default; typos like `plainjson` or `json` in the format header.

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/2904fe7a39a52423. Report an issue: GitHub.