oven-sh/bun · error · Error

Required argument cannot follow an optional argument

Error message

Required argument ${name} cannot follow an optional argument

What it means

Thrown by validateVariant in the bindgen code generator when parsing a .bind.ts variant: an argument without `optional` or `default` flags appears after an argument that has one. This ordering cannot be expressed in the generated JavaScript signature (JS positional args cannot be required after an optional slot), so the generator aborts. The input at fault is the args object of the variant being validated.

Solutions

  1. Reorder the variant's arguments so all required arguments come before optional/defaulted ones
  2. Give the offending required argument a default value or mark it optional
  3. If the argument is synthesized by the generator rather than user-facing, mark it as a virtual argument so the ordering check skips it
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src/codegen/bindgen-lib-internal.ts:843 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/1e99192d48a7eefb. Report an issue: GitHub.

Appendix: source

Thrown at src/codegen/bindgen-lib-internal.ts:843

  return func;
}

function validateVariant(variant: any) {
  let minRequiredArgs = 0;
  let seenOptionalArgument = false;
  let i = 0;

  for (const [name, type] of Object.entries(variant.args) as [string, TypeImpl][]) {
    if (!(type instanceof TypeImpl)) {
      throw new Error(`Expected type for argument ${name}, got ${inspect(type)}`);
    }
    i += 1;
    if (type.isVirtualArgument()) {
      continue;
    }
    if (!type.flags.optional && !("default" in type.flags)) {
      if (seenOptionalArgument) {
        throw new Error(`Required argument ${name} cannot follow an optional argument`);
      }
      minRequiredArgs++;
    } else {
      seenOptionalArgument = true;
    }
  }

  return { minRequiredArgs };
}

function snapshotCallerLocation(): string {
  const stack = new Error().stack!;
  const lines = stack.split("\n");
  let i = 1;
  for (; i < lines.length; i++) {
    if (!lines[i].includes(import.meta.dir)) {
      return lines[i];
    }

View on GitHub (pinned to 8c5296ac45)