{"record":{"id":"3de7b96ffeae50ba","repo":"karatelabs/karate","slug":"toindex-value-must-be-non-negative","errorCode":null,"errorMessage":"ToIndex: value must be non-negative","messagePattern":"ToIndex: value must be non-negative","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsBigIntConstructor.java","lineNumber":159,"sourceCode":"        if (bits == 0) return BigInteger.ZERO;\n        BigInteger mod = BigInteger.ONE.shiftLeft(bits);\n        return bi.mod(mod);\n    }\n\n    // Spec ToIndex: ToPrimitive(\"number\") → ToNumber → ToInteger, then RangeError if\n    // negative. Truncate fires *before* the negative check, so -0.9 → 0 (not RangeError).\n    // NaN / undefined / null / false / \"\" all collapse to 0.\n    private static int toIndex(Object value, CoreContext context) {\n        if (value instanceof ObjectLike) {\n            value = Terms.toPrimitive(value, \"number\", context);\n            if (context != null && context.isError()) return 0;\n        }\n        Number n = Terms.objectToNumber(value);\n        double d = n.doubleValue();\n        if (Double.isNaN(d) || d == 0) return 0;\n        long truncated = (long) d; // Java cast: truncate toward zero\n        if (truncated < 0) {\n            throw JsErrorException.rangeError(\"ToIndex: value must be non-negative\");\n        }\n        return (int) truncated;\n    }\n\n}\n","sourceCodeStart":141,"sourceCodeEnd":165,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsBigIntConstructor.java#L141-L165","documentation":"BigInt.asIntN(bits, value) and BigInt.asUintN coerce their first argument through the spec's ToIndex, which requires an integral, non-negative number. A negative number (or any number truncating below zero) throws this RangeError in Karate's JS engine.","triggerScenarios":"BigInt.asIntN(-1, 5n), BigInt.asIntN(width, x) where width is a negative computed variable, BigInt.asUintN(size - overflow, v) with a size smaller than the subtracted amount.","commonSituations":"Bit-width read from config/environment that is unset or negative; arithmetic like maxWidth - padding going negative; copy-pasted code passing the value as the first argument instead of the bit count.","solutions":["Clamp the width before the call: BigInt.asIntN(Math.max(0, w), v)","Validate w is a non-negative integer: if (!Number.isInteger(w) || w < 0) throw new RangeError('bad width')","Check argument order — bits come first, the BigInt second","Sanitize config-sourced widths at load time with defaults (w = Number.isInteger(cfg.width) && cfg.width >= 0 ? cfg.width : 32)"],"exampleFix":"// before\nlet masked = BigInt.asIntN(bits, value); // bits = -8 from config\n// after\nlet masked = BigInt.asIntN(Math.max(0, bits | 0), value);","handlingStrategy":"validation","validationCode":"function asIntNSafe(bits, value) {\n  if (!Number.isInteger(bits) || bits < 0) throw new RangeError('bits must be a non-negative integer');\n  return BigInt.asIntN(bits, value);\n}","typeGuard":null,"tryCatchPattern":"let masked;\ntry { masked = BigInt.asIntN(bits, v); } catch (e) {\n  if (e instanceof RangeError && /non-negative/.test(e.message)) masked = BigInt.asIntN(64, v);\n  else throw e;\n}","preventionTips":["Validate bit widths from config/env as non-negative integers at load time","Remember argument order: bits first, BigInt second","Clamp computed widths with Math.max(0, w)","Unit-test width arithmetic (subtractions) that can go negative"],"tags":["javascript","bigint","range-error","toindex"],"backgroundTag":"value-out-of-range","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}