{"record":{"id":"55a94df4b0b77504","repo":"denoland/deno","slug":"delay-must-be-0-received-delay","errorCode":null,"errorMessage":"Delay must be >= 0: received ${delay}","messagePattern":"Delay must be >= 0: received (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/kv/01_db.ts","lineNumber":68,"sourceCode":"\nconst cloneableDeserializers = core.getCloneableDeserializers();\n\nconst encodeCursor: (\n  selector: [Deno.KvKey | null, Deno.KvKey | null, Deno.KvKey | null],\n  boundaryKey: Deno.KvKey,\n) => string = (selector, boundaryKey) =>\n  op_kv_encode_cursor(selector, boundaryKey);\n\nasync function openKv(path: string) {\n  const rid = await op_kv_database_open(path);\n  return new Kv(rid, kvSymbol);\n}\n\nconst maxQueueDelay = 30 * 24 * 60 * 60 * 1000;\n\nfunction validateQueueDelay(delay: number) {\n  if (delay < 0) {\n    throw new TypeError(`Delay must be >= 0: received ${delay}`);\n  }\n  if (delay > maxQueueDelay) {\n    throw new TypeError(\n      `Delay cannot be greater than 30 days: received ${delay}`,\n    );\n  }\n  if (NumberIsNaN(delay)) {\n    throw new TypeError(\"Delay cannot be NaN\");\n  }\n}\n\nfunction validateExpireIn(expireIn: number | undefined) {\n  if (expireIn === undefined) return;\n  // Reject NaN, Infinity, fractional and negative values. A non-finite\n  // expireIn otherwise reaches the native layer and overflows when computing\n  // the absolute expiry, panicking the process.\n  if (!NumberIsInteger(expireIn) || expireIn < 0) {\n    throw new TypeError(","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/kv/01_db.ts#L50-L86","documentation":"`Deno.Kv.enqueue(value, { delay })` schedules a message for future delivery; `validateQueueDelay` rejects a negative `delay` up front because a negative offset would target a time in the past, which the queue can never honor.","triggerScenarios":"`kv.enqueue(msg, { delay: -100 })`; delays computed from timestamps that invert, e.g. `deadline - Date.now()` when the deadline has already passed by the time of the call.","commonSituations":"Deadline/reminder scheduling where the target time slipped into the past before enqueueing; unit confusion after converting seconds to ms and subtracting; porting cron-like logic that assumes clamping.","solutions":["Clamp before the call: `delay = Math.max(0, delay)`","Validate the computed delta and skip/log expired deadlines instead of enqueueing","Confirm you pass a relative duration in milliseconds, not an absolute timestamp"],"exampleFix":"// before\nconst delay = deadline - Date.now(); // negative when deadline passed\nawait kv.enqueue(job, { delay });\n\n// after\nconst delay = Math.max(0, deadline - Date.now());\nawait kv.enqueue(job, { delay });","handlingStrategy":"validation","validationCode":"const delay = Math.max(0, Number(opts.delay ?? 0));\nif (!Number.isFinite(delay)) throw new Error(`bad delay: ${opts.delay}`);\nawait kv.enqueue(msg, { delay });","typeGuard":"const isValidQueueDelay = (d: unknown): d is number =>\n  typeof d === \"number\" && Number.isFinite(d) && d >= 0;","tryCatchPattern":null,"preventionTips":["Clamp computed deltas (deadline - Date.now()) with Math.max(0, ...)","Centralize enqueue options in one helper that validates delay/keys/backoffSchedule","Treat delay as relative milliseconds, never absolute timestamps"],"tags":["kv","deno-kv","queue","enqueue","validation"],"backgroundTag":"delay-out-of-range","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}