denoland/deno · error · TypeError
Delay cannot be greater than 30 days: received ${delay}
Error message
Delay cannot be greater than 30 days: received ${delay} What it means
validateQueueDelay also enforces an upper bound: kv.enqueue's delay may not exceed 30 days (maxQueueDelay = 30*24*60*60*1000 ms). Longer deferrals are rejected because the queue's scheduler does not support month-scale delays.
Source
Thrown at ext/kv/01_db.ts:71
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(
`expireIn must be a non-negative integer: received ${expireIn}`,
);
}View on GitHub (pinned to 89f33cbef2)
Solutions
- Cap the delay at 30 days or schedule for <= 30 days out.
- For longer deferrals, enqueue a 'check' message that re-enqueues with another delay when the time hasn't come yet (chained enqueue).
- If you passed a timestamp by mistake, subtract now: delay = runAt - Date.now(), then clamp to [0, 30 days].
Example fix
// before
await kv.enqueue({ type: "renew" }, { delay: runAtMs }); // runAtMs ~ epoch -> huge
// after
const delay = Math.min(Math.max(0, runAtMs - Date.now()), 30 * 24 * 60 * 60 * 1000);
await kv.enqueue({ type: "renew" }, { delay }); Defensive patterns
Strategy: validation
Validate before calling
const MAX_DELAY = 30 * 24 * 60 * 60 * 1000;
const delay = Math.min(Math.max(0, runAt - Date.now()), MAX_DELAY);
await kv.enqueue(job, { delay }); Type guard
function isEnqueueDelay(d: unknown): d is number { return typeof d === "number" && Number.isFinite(d) && d >= 0 && d <= 30 * 24 * 60 * 60 * 1000; } Prevention
- Cap delays at 30 days at the call site.
- For longer waits, chain enqueues via a re-check message.
- Beware timestamp-vs-duration mixups: always subtract Date.now().
When it happens
Trigger: kv.enqueue(msg, { delay: 45 * 24 * 60 * 60 * 1000 }); passing an absolute epoch timestamp as delay (seconds or ms); computing delay from a far-future calendar date; 'remind me in a year' features implemented directly on enqueue.
Common situations: Timestamp-vs-duration confusion (delay: Date.now() + week); long-term reminders or expirations; config-driven retry horizons larger than intended; copy from systems that allow arbitrary TTLs.
Related errors
- Delay must be >= 0: received ${delay}
- Invalid backoffSchedule, max ${maxQueueBackoffIntervals} int
- Delay cannot be NaN
- Invalid backoffSchedule, interval at index ${i} is invalid
- Invalid cron schedule: start=${start}, end=${end}, every=${e
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/97472e1eee0d2e41.
Report an issue: GitHub.