{"record":{"id":"4f60e082a2ccf9a8","repo":"gitbutlerapp/gitbutler","slug":"invalidarg","errorCode":"InvalidArg","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":1560,"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":1542,"sourceCodeEnd":1578,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but-api-macros/src/lib.rs#L1542-L1578","documentation":"Generated by but-api-macros for napi-exported functions taking usize: the JS value arrives as i64 and is narrowed with TryFrom; a negative number (or a value beyond the platform usize range, relevant on 32-bit builds) yields napi Status::InvalidArg with this message naming the argument. It is a boundary type-check that runs before the Rust function executes; fractional/NaN input is rejected earlier by napi's own number conversion.","triggerScenarios":"From Node/Electron, calling a generated but-api binding whose Rust signature takes usize with -1 (a common 'unlimited' sentinel), values above Number.MAX_SAFE_INTEGER, or values above u32 range on 32-bit targets.","commonSituations":"UI code passing -1 as 'no limit'; arithmetic overflow producing huge counts in computed sizes; JSON configs deserialized with negative defaults.","solutions":["Validate in JS before the call: integer, >= 0, and <= Number.MAX_SAFE_INTEGER.","Replace -1 sentinels with an explicit optional/null parameter in the binding signature.","Clamp or reject out-of-range inputs with a user-facing message at the caller."],"exampleFix":"// before\nawait listEntries({ limit: -1 }); // \"argument 'limit' must be a non-negative integer...\"\n\n// after\nconst limit = userLimit < 0 ? undefined : userLimit; // omit to use the Rust default\nawait listEntries({ limit });","handlingStrategy":"validation","validationCode":"if (!Number.isInteger(limit) || limit < 0 || !Number.isSafeInteger(limit)) {\n  throw new TypeError('limit must be a non-negative safe integer');\n}","typeGuard":"const isUsize = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isInteger(v) && v >= 0 && v <= Number.MAX_SAFE_INTEGER;","tryCatchPattern":null,"preventionTips":["Avoid negative sentinel values in JS-to-Rust APIs; model optionals explicitly.","Assert integer ranges at the JS boundary with a shared helper.","Keep numeric API parameters within safe-integer range by design."],"tags":["napi","nodejs","integer","validation","type-conversion"],"backgroundTag":"napi-integer-overflow","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}