denoland/deno · error · TypeError
Delay must be >= 0: received
Error message
Delay must be >= 0: received ${delay} What it means
`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.
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
Example fix
// before
const delay = deadline - Date.now(); // negative when deadline passed
await kv.enqueue(job, { delay });
// after
const delay = Math.max(0, deadline - Date.now());
await kv.enqueue(job, { delay }); Defensive patterns
Strategy: validation
Validate before calling
const delay = Math.max(0, Number(opts.delay ?? 0));
if (!Number.isFinite(delay)) throw new Error(`bad delay: ${opts.delay}`);
await kv.enqueue(msg, { delay }); Type guard
const isValidQueueDelay = (d: unknown): d is number => typeof d === "number" && Number.isFinite(d) && d >= 0;
Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- Delay cannot be greater than 30 days: received
- Delay cannot be NaN
- Invalid backoffSchedule, interval at index
- Invalid backoffSchedule, max
- expireIn must be a non-negative integer: received
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/55a94df4b0b77504.
Report an issue: GitHub.
Appendix: source
Thrown at ext/kv/01_db.ts:68
const cloneableDeserializers = core.getCloneableDeserializers();
const encodeCursor: (
selector: [Deno.KvKey | null, Deno.KvKey | null, Deno.KvKey | null],
boundaryKey: Deno.KvKey,
) => string = (selector, boundaryKey) =>
op_kv_encode_cursor(selector, boundaryKey);
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(View on GitHub (pinned to 9ad36f7a2c)