gitbutlerapp/gitbutler · error · napi::Error

argument ' ' must be an integer that fits in isize

Error message

argument '{}' must be an integer that fits in isize

What it means

Same mechanism as the usize case: the macro converts the incoming napi integer into Rust isize via TryFrom and fails when the value doesn't fit in isize (larger than isize::MAX on the platform, typically only from huge JS numbers).

Solutions

  1. Validate the number fits within Number.MIN_SAFE_INTEGER..Number.MAX_SAFE_INTEGER and is an integer before calling
  2. Convert BigInt values down to safe Numbers only when actually in range
  3. Check where the oversized number originates (IDs concatenated as numbers are a common cause)

Example fix

// before
api.seek(2 ** 63)  // exceeds isize
// after
api.seek(Number.MAX_SAFE_INTEGER)
Defensive patterns

Strategy: validation

Validate before calling

const fitsIsize = (n) => Number.isInteger(n) && Math.abs(n) <= Number.MAX_SAFE_INTEGER;

Type guard

const fitsIsize = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v <= Number.MAX_SAFE_INTEGER;

Try / catch

try { api.call(n); } catch (e) { if (/fits in isize/.test(e.message)) console.error('number too large:', n); throw e; }

Prevention

When it happens

Trigger: Calling a generated but_api NAPI function with an isize-remapped parameter receiving a value beyond isize::MAX (e.g. a JS Number larger than ~9.2e18) or a non-integer.

Common situations: Passing an unvalidated timestamp/ID from JS where a float or oversized Number (e.g. from Date.now() arithmetic or a concatenated ID) exceeds isize range.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/ca474508fff232de. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-api-macros/src/lib.rs:1672

                        // Type needs remapping (e.g., usize → i64)
                        params.push(quote! { #ident: #napi_ty });
                        names.push(ident.to_string());
                        let arg_name = ident.to_string();
                        let conversion = match type_name.as_deref() {
                            Some("usize") => quote! {
                                let #ident: usize = ::std::convert::TryFrom::try_from(#ident).map_err(|_| {
                                    napi::Error::new(
                                        napi::Status::InvalidArg,
                                        format!(
                                            "argument '{}' must be a non-negative integer that fits in usize",
                                            #arg_name
                                        ),
                                    )
                                })?;
                            },
                            Some("isize") => quote! {
                                let #ident: isize = ::std::convert::TryFrom::try_from(#ident).map_err(|_| {
                                    napi::Error::new(
                                        napi::Status::InvalidArg,
                                        format!(
                                            "argument '{}' must be an integer that fits in isize",
                                            #arg_name
                                        ),
                                    )
                                })?;
                            },
                            _ => quote! {},
                        };
                        conversions.push(conversion);
                        call_arg_idents.push(quote! { #ident });
                    } else if is_simple_napi_type(base_ty) {
                        // Simple types (String, bool, numbers) can be passed directly
                        params.push(quote! { #ident: #ty });
                        names.push(ident.to_string());
                        call_arg_idents.push(quote! { #ident });
                    } else {

View on GitHub (pinned to 58e5313667)