{"record":{"id":"775918f01c2a50ee","repo":"gitbutlerapp/gitbutler","slug":"argument-must-be-a-non-negative-integer-that-fits-in-usize","errorCode":null,"errorMessage":"argument '{}' must be a non-negative integer that fits in usize","messagePattern":"argument '(.+?)' must be a non-negative integer that fits in usize","errorType":"validation","errorClass":"napi::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api-macros/src/lib.rs","lineNumber":1661,"sourceCode":"                    names.push(ident.to_string());\n                    conversions.push(quote! {\n                        let #ident: crate::json::HexHash = ::std::str::FromStr::from_str(&#ident)\n                            .map(crate::json::HexHash)\n                            .map_err(|e: gix::hash::decode::Error| napi::Error::new(napi::Status::InvalidArg, format!(\"{e}\")))?;\n                    });\n                    call_arg_idents.push(quote! { #ident });\n                }\n                _ => {\n                    // For all other types: check for napi-incompatible types first\n                    if let Some(napi_ty) = napi_type_remap(base_ty) {\n                        // Type needs remapping (e.g., usize → i64)\n                        params.push(quote! { #ident: #napi_ty });\n                        names.push(ident.to_string());\n                        let arg_name = ident.to_string();\n                        let conversion = match type_name.as_deref() {\n                            Some(\"usize\") => quote! {\n                                let #ident: usize = ::std::convert::TryFrom::try_from(#ident).map_err(|_| {\n                                    napi::Error::new(\n                                        napi::Status::InvalidArg,\n                                        format!(\n                                            \"argument '{}' must be a non-negative integer that fits in usize\",\n                                            #arg_name\n                                        ),\n                                    )\n                                })?;\n                            },\n                            Some(\"isize\") => quote! {\n                                let #ident: isize = ::std::convert::TryFrom::try_from(#ident).map_err(|_| {\n                                    napi::Error::new(\n                                        napi::Status::InvalidArg,\n                                        format!(\n                                            \"argument '{}' must be an integer that fits in isize\",\n                                            #arg_name\n                                        ),\n                                    )\n                                })?;","sourceCodeStart":1643,"sourceCodeEnd":1679,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-api-macros/src/lib.rs#L1643-L1679","documentation":"The but_api macro converts napi integer parameters (i64/f64 on the JS side) into Rust usize via TryFrom. When the supplied value is negative or exceeds the platform usize range, the conversion fails and this InvalidArg error names the argument.","triggerScenarios":"Calling a generated but_api NAPI function whose parameter is remapped to usize and passing a negative number, a value above usize::MAX (rare on 64-bit), or a non-integral JS number.","commonSituations":"Frontend computes a limit/offset/index that went negative (e.g. cursor - pageSize), or passes -1 as a sentinel 'unlimited' value which the API does not accept.","solutions":["Clamp or validate the value to be a non-negative integer before the call","Replace sentinel negative values with the API's explicit option (e.g. omit the parameter)","Check the arithmetic upstream that produced the negative value"],"exampleFix":"// before\napi.listCommits(-10)\n// after\napi.listCommits(Math.max(0, offset))","handlingStrategy":"validation","validationCode":"const isNonNegativeInt = (n) => Number.isInteger(n) && n >= 0;","typeGuard":"const isNonNegativeInt = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v >= 0;","tryCatchPattern":"try { api.list(x); } catch (e) { if (/fits in usize/.test(e.message)) console.error('argument must be >= 0'); throw e; }","preventionTips":["Clamp computed indices/offsets with Math.max(0, value)","Avoid -1 sentinels; use optional/omitted params instead","Add range assertions in tests around pagination arithmetic"],"tags":["napi","usize","integer-overflow","invalid-argument"],"backgroundTag":"value-out-of-range","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}