risingwavelabs/risingwave · warning

invalid webhook JSON decoder option

Error message

invalid webhook JSON decoder option

What it means

The value of a timestamptz-handling header (`x-rw-webhook-json-timestamptz-handling`) could not be parsed by `TimestamptzHandling::from_options`. The inner error from that parser explains the specific problem; the wrapper marks it as an invalid webhook JSON decoder option and returns HTTP 400 BAD_REQUEST.

Source

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

        Some(value) => Err(err(
            anyhow!("unrecognized value `{value}` for `{key}`"),
            StatusCode::BAD_REQUEST,
        )),
        None => Ok(None),
    }
}

fn parse_timestamptz_handling(
    headers: &HeaderMap,
    key: &'static str,
) -> Result<Option<TimestamptzHandling>> {
    header_value(headers, key)?
        .as_deref()
        .map(TimestamptzHandling::from_options)
        .transpose()
        .map_err(|e| {
            err(
                anyhow!(e).context("invalid webhook JSON decoder option"),
                StatusCode::BAD_REQUEST,
            )
        })
}

fn parse_time_handling(headers: &HeaderMap, key: &'static str) -> Result<Option<TimeHandling>> {
    match header_value(headers, key)?.as_deref() {
        Some("milli") => Ok(Some(TimeHandling::Milli)),
        Some("micro") => Ok(Some(TimeHandling::Micro)),
        Some(value) => Err(err(
            anyhow!("unrecognized value `{value}` for `{key}`"),
            StatusCode::BAD_REQUEST,
        )),
        None => Ok(None),
    }
}

fn parse_bigint_unsigned_handling(

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Read the inner error to identify exactly which timestamptz option failed.
  2. Use only documented timestamptz handling values for your RisingWave version.
  3. Remove the header to fall back to default timestamptz behavior.
  4. Check `TimestamptzHandling::from_options` in the source for the accepted option syntax.
  5. Test the header combination with a single curl request before enabling it in production.

Example fix

// before
-H 'x-rw-webhook-json-timestamptz-handling: utc+garbage'
// after: remove the header (default) or use a documented mode
// -H 'x-rw-webhook-json-timestamptz-handling: <documented-mode>'
Defensive patterns

Strategy: validation

Validate before calling

// only send the header when the value is a documented mode
const SUPPORTED = ['milli', 'guess_number_unit']; // confirm against your RW version's TimestamptzHandling docs
const v = headers['x-rw-webhook-json-timestamptz-handling'];
if (v && !SUPPORTED.includes(String(v))) throw new Error(`invalid timestamptz option: ${v}`);

Try / catch

try {
  const res = await fetch(url, { method: 'POST', headers, body });
  if (res.status === 400 && (await res.text()).includes('invalid webhook JSON decoder option')) {
    delete headers['x-rw-webhook-json-timestamptz-handling']; // fall back to defaults
    return fetch(url, { method: 'POST', headers, body });
  }
} catch (e) { log(e); }

Prevention

When it happens

Trigger: POST with an unsupported or malformed timestamptz option value in the `x-rw-webhook-json-*` header (unknown handling mode, or an option string whose format `from_options` does not accept).

Common situations: Typos in option names; an SDK emitting option strings from a different RisingWave version; manually constructed headers with wrong option syntax (separators/flags).

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