denoland/deno · error · NodeRangeError

ERR_OUT_OF_RANGE

ERR_OUT_OF_RANGE

Error message

The value of "candidate" is out of range. It must be >= 0. Received ${candidate}

What it means

Thrown by Deno's node:crypto polyfill for checkPrime() (ext/node/polyfills/internal/crypto/random.ts:94) when the candidate argument is a negative BigInt. checkPrime runs probabilistic primality tests and only makes sense for non-negative integers, so any candidate < 0n is rejected before the native op is invoked. The async checkPrime and its callback are never reached; the error is thrown synchronously.

Source

Thrown at ext/node/polyfills/internal/crypto/random.ts:94

) {
  if (typeof options === "function") {
    callback = options;
    options = {};
  }

  validateFunction(callback, "callback");
  validateObject(options, "options");

  const {
    checks = 0,
  } = options!;

  validateInt32(checks, "options.checks", 0);

  let candidateBytes: ArrayBufferView | ArrayBuffer;
  if (typeof candidate === "bigint") {
    if (candidate < 0) {
      throw new ERR_OUT_OF_RANGE("candidate", ">= 0", candidate);
    }
    candidateBytes = bigintToBytes(candidate);
  } else if (isAnyArrayBuffer(candidate) || isArrayBufferView(candidate)) {
    const byteLength = isArrayBufferView(candidate)
      ? arrayBufferViewByteLength(candidate as ArrayBufferView)
      : ArrayBufferPrototypeGetByteLength(candidate as ArrayBuffer);
    if (byteLength > OPENSSL_BIGNUM_MAX_BYTES) {
      throw new NodeError(
        "ERR_OSSL_BN_BIGNUM_TOO_LONG",
        "bignum too long",
      );
    }
    candidateBytes = candidate;
  } else {
    throw new ERR_INVALID_ARG_TYPE(
      "candidate",
      [
        "ArrayBuffer",

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Ensure the candidate BigInt is non-negative before calling checkPrime (mask sign with BigInt.asUintN(bitLength, value) if the value came from signed bytes).
  2. If the value legitimately can be negative, reject or absolute-value it in your own code first — primality of a negative number is not a meaningful query.
  3. Pass the number as a Buffer/Uint8Array of unsigned bytes instead of a BigInt, since only the bigint branch checks sign.

Example fix

// before
const p = maybeNegative;
crypto.checkPrime(p, (err, is) => {});

// after
const p = BigInt.asUintN(2048, maybeNegative);
if (p <= 0n) throw new RangeError('candidate must be positive');
crypto.checkPrime(p, (err, is) => {});
Defensive patterns

Strategy: validation

Validate before calling

if (typeof candidate === 'bigint' && candidate < 0n) throw new RangeError('candidate must be >= 0');

Type guard

const isPrimeCandidate = (v) => (typeof v === 'bigint' ? v >= 0n : ArrayBuffer.isView(v) || v instanceof ArrayBuffer);

Try / catch

try { crypto.checkPrime(c, cb); } catch (e) { if (e.code === 'ERR_OUT_OF_RANGE') { /* normalize candidate and retry once */ } else throw e; }

Prevention

When it happens

Trigger: Calling crypto.checkPrime(-7n, cb) or crypto.checkPrime(-1n, { checks: 16 }, cb). Also hit when a computed BigInt (e.g. a subtraction or a value parsed from signed two's-complement bytes without masking) goes negative and is passed as candidate.

Common situations: Diffie-Hellman or prime-search code that derives candidates arithmetically; converting signed buffers to BigInt with BigInt.asIntN instead of BigInt.asUintN; unit tests feeding boundary values like -0n's neighbors.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/18db44ceaf4e04a0. Report an issue: GitHub.