denoland/deno · error · TypeError

Delay cannot be NaN

Error message

Delay cannot be NaN

What it means

The third check in `validateQueueDelay`: comparisons against NaN are false, so NaN slips past the `< 0` and `> max` tests and is caught explicitly with this dedicated message. `kv.enqueue(..., { delay: NaN })` therefore throws before the op runs.

Solutions

  1. Default missing values: `delay ?? 0`
  2. Validate with `Number.isFinite(delay)` before the enqueue
  3. Fix the upstream computation that produced the NaN

Example fix

// before
await kv.enqueue(job, { delay: opts.delayMs * factor }); // NaN when delayMs undefined

// after
const delay = Number.isFinite(opts.delayMs) ? opts.delayMs * factor : 0;
await kv.enqueue(job, { delay });
Defensive patterns

Strategy: validation

Validate before calling

if (!Number.isFinite(delay)) {
  throw new Error(`delay is not a finite number: ${delay}`);
}
await kv.enqueue(msg, { delay });

Type guard

const isFiniteNumber = (v: unknown): v is number =>
  typeof v === "number" && Number.isFinite(v);

Prevention

When it happens

Trigger: `delay: undefined * 1000` (undefined config multiplied); `Number.parseInt('soon')`-style parse failures; arithmetic on missing option values such as `options.delayMs * multiplier` where `delayMs` is undefined.

Common situations: Optional config that arrives as undefined; parsing user-supplied delay input; computing a delay from a missing field on an object.

Related errors


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

Appendix: source

Thrown at ext/kv/01_db.ts:76

async function openKv(path: string) {
  const rid = await op_kv_database_open(path);
  return new Kv(rid, kvSymbol);
}

const maxQueueDelay = 30 * 24 * 60 * 60 * 1000;

function validateQueueDelay(delay: number) {
  if (delay < 0) {
    throw new TypeError(`Delay must be >= 0: received ${delay}`);
  }
  if (delay > maxQueueDelay) {
    throw new TypeError(
      `Delay cannot be greater than 30 days: received ${delay}`,
    );
  }
  if (NumberIsNaN(delay)) {
    throw new TypeError("Delay cannot be NaN");
  }
}

function validateExpireIn(expireIn: number | undefined) {
  if (expireIn === undefined) return;
  // Reject NaN, Infinity, fractional and negative values. A non-finite
  // expireIn otherwise reaches the native layer and overflows when computing
  // the absolute expiry, panicking the process.
  if (!NumberIsInteger(expireIn) || expireIn < 0) {
    throw new TypeError(
      `expireIn must be a non-negative integer: received ${expireIn}`,
    );
  }
}

const maxQueueBackoffIntervals = 5;
const maxQueueBackoffInterval = 60 * 60 * 1000;

View on GitHub (pinned to 9ad36f7a2c)