napi-rs/napi-rs · error · InvalidArg

Invalid number of arguments

Error message

Invalid number of arguments

What it means

Raised in the macro-generated `TupleFromSliceValues` when the number of JS arguments does not exactly match the Rust tuple arity: `values.try_into()` on the slice fails and the library maps it to InvalidArg "Invalid number of arguments". It enforces strict fixed-arity calls for tuple-typed function parameters.

Solutions

  1. Pass exactly the number of arguments declared in the generated .d.ts signature.
  2. Use undefined for Option<T> parameters if the signature allows them, instead of omitting positions.
  3. Regenerate/inspect index.d.ts after changing the Rust function and update all call sites.
  4. Add a JS-side arity check before invoking the native function.

Example fix

// before
mod.add(1);
// after
mod.add(1, 2);
Defensive patterns

Strategy: validation

Validate before calling

function assertArity(args, n) { if (args.length !== n) throw new Error(`expected ${n} args, got ${args.length}`); }
assertArity([a, b], 2);

Try / catch

try { mod.add(a, b); } catch (e) { if (e.message === 'Invalid number of arguments') console.error('check the .d.ts signature'); throw e; }

Prevention

When it happens

Trigger: Calling a native function with too few or too many arguments relative to its declared Rust parameters, e.g. calling `fn add(a: u32, b: u32)` with `add(1)` or `add(1, 2, 3)`. Also when a wrapper/macro passes a slice of args of the wrong length.

Common situations: API signature changed after a rebuild while old JS call sites remain; optional-argument calls against functions without Option parameters; spreading arrays with unexpected length.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of napi-rs/napi-rs@39bd1205e4 (2026-09-13). Data as JSON: /api/errors/4a443310c25c49dc. Report an issue: GitHub.

Appendix: source

Thrown at crates/napi/src/bindgen_runtime/js_values/function.rs:67

    FnArgs { data: value }
  }
}

macro_rules! impl_tuple_conversion {
  ($($ident:ident),*) => {
    impl<$($ident: ToNapiValue),*> JsValuesTupleIntoVec for FnArgs<($($ident,)*)> {
      #[allow(clippy::not_unsafe_ptr_arg_deref)]
      fn into_vec(self, env: sys::napi_env) -> Result<Vec<sys::napi_value>> {
        #[allow(non_snake_case)]
        let ($($ident,)*) = self.data;
        Ok(vec![$(unsafe { <$ident as ToNapiValue>::to_napi_value(env, $ident)? }),*])
      }
    }

    impl<$($ident: FromNapiValue),*> TupleFromSliceValues for ($($ident,)*) {
      unsafe fn from_slice_values(env: sys::napi_env, values: &[sys::napi_value]) -> $crate::Result<Self> {
        #[allow(non_snake_case)]
        let [$($ident),*] = values.try_into().map_err(|_| crate::Error::new(
          crate::Status::InvalidArg,
          "Invalid number of arguments",
        ))?;
        Ok(($(
          unsafe { $ident::from_napi_value(env, $ident)?}
        ,)*))
      }
    }
  };
}

impl_tuple_conversion!(A);
impl_tuple_conversion!(A, B);
impl_tuple_conversion!(A, B, C);
impl_tuple_conversion!(A, B, C, D);
impl_tuple_conversion!(A, B, C, D, E);
impl_tuple_conversion!(A, B, C, D, E, F);
impl_tuple_conversion!(A, B, C, D, E, F, G);

View on GitHub (pinned to 39bd1205e4)