rolldown/rolldown · error

expected a number payload, but got

Error message

expected a number payload, but got {other:?}

What it means

Napi-side type guard in BindingFilterTokenPayloadInner::try_into_number: the filter-expression token payload received from JavaScript was expected to hold a number, but the actual payload variant is shown in the message (e.g. StringOrRegex). It fires when a filter expression built on the JS side places a non-number payload where the consuming token requires a number.

Solutions

  1. Pass an actual JS number (not a numeric string) for number tokens
  2. Check token array alignment — a missing token shifts payloads against kinds
  3. Coerce numeric strings with `Number(value)` before constructing the token

Example fix

// before
{ kind: 'queryKey', payload: '1' }
// after
{ kind: 'queryKey', payload: 1 }
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof payload !== 'number' || Number.isNaN(payload)) {
  throw new TypeError('number token payload required');
}

Type guard

function isNumber(v) {
  return typeof v === 'number' && !Number.isNaN(v);
}

Try / catch

try {
  const n = payload.tryIntoNumber();
} catch (e) {
  console.error('Expected numeric token payload:', e.message);
  throw e;
}

Prevention

When it happens

Trigger: Calling `try_into_number()` on a `StringOrRegex` or `Boolean` payload, e.g. a token intended as numeric (like a query value kind) but built with a string payload.

Common situations: Building filter expression tokens programmatically where a numeric token receives a stringified number (`'1'` instead of `1`), or token arrays shifted so the payload pairs with the wrong kind.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of rolldown/rolldown@91b44b9d7b (2026-09-07). Data as JSON: /api/errors/dda7765335c5c601. Report an issue: GitHub.

Appendix: source

Thrown at crates/rolldown_binding/src/options/plugin/types/binding_filter_expression.rs:36

impl BindingFilterTokenPayloadInner {
  pub fn try_into_string(self) -> anyhow::Result<String> {
    match self {
      BindingFilterTokenPayloadInner::StringOrRegex(inner) => inner.try_into_string(),
      other => anyhow::bail!("expected a string payload, but got {other:?}"),
    }
  }

  pub fn try_into_string_or_regex(self) -> anyhow::Result<StringOrRegex> {
    match self {
      BindingFilterTokenPayloadInner::StringOrRegex(inner) => Ok(inner),
      other => anyhow::bail!("expected a string or regex payload, but got {other:?}"),
    }
  }

  pub fn try_into_number(self) -> anyhow::Result<u32> {
    match self {
      BindingFilterTokenPayloadInner::Number(v) => Ok(v),
      other => anyhow::bail!("expected a number payload, but got {other:?}"),
    }
  }

  pub fn try_into_regex(self) -> anyhow::Result<HybridRegex> {
    match self {
      BindingFilterTokenPayloadInner::StringOrRegex(inner) => inner.try_into_regex(),
      other => anyhow::bail!("expected a regex payload, but got {other:?}"),
    }
  }
}

#[derive(Debug, Clone)]
pub struct BindingFilterTokenPayload(BindingFilterTokenPayloadInner);

impl BindingFilterTokenPayload {
  pub fn into_inner(self) -> BindingFilterTokenPayloadInner {
    self.0
  }

View on GitHub (pinned to 91b44b9d7b)