n8n-io/n8n · error · InvalidScheduleError
one_off.fireAt must be a valid Date
Error message
one_off.fireAt must be a valid Date
What it means
Thrown by validateOneOff when schedule.fireAt is not a Date instance or is an Invalid Date (getTime() returns NaN). Like the cron validator, oneOff guards `unknown` because raw DB rows can arrive untyped - a string timestamp or a number would otherwise produce a confusing downstream error.
Source
Thrown at packages/@n8n/scheduler/src/core/recurrence/kinds/one-off.ts:13
import { InvalidScheduleError } from '../../errors';
import type { OneOffSchedule, ScheduledJob } from '../../types';
import { required } from '../field';
/**
* Checks that a one-off schedule has a valid fire time.
* @param schedule The one-off schedule to check.
* @throws {InvalidScheduleError} When `fireAt` is not a valid Date.
*/
export function validateOneOff(schedule: OneOffSchedule): void {
const fireAt: unknown = schedule.fireAt;
if (!(fireAt instanceof Date) || Number.isNaN(fireAt.getTime())) {
throw new InvalidScheduleError('one_off.fireAt must be a valid Date');
}
}
/**
* The one-off fire time, or `null` if it has already passed.
* @param schedule The one-off schedule.
* @param after The instant to fire after.
* @returns `fireAt` when it is still ahead of `after`, otherwise `null`.
*/
export function oneOffNextRun(schedule: OneOffSchedule, after: Date): Date | null {
return after.getTime() < schedule.fireAt.getTime() ? schedule.fireAt : null;
}
/**
* The single fire of a one-off schedule: just `first`, then nothing.
* @param first The one-off's fire time.
* @returns A generator that yields `first` once.
*/View on GitHub (pinned to 5ac6606e81)
Solutions
- Map the DB column to a Date in your ORM/driver config (TypeORM: { type: 'timestamp' } yields Date).
- When deserializing from JSON, wrap: fireAt: new Date(raw.fireAt).
- Validate with `value instanceof Date && !Number.isNaN(value.getTime())` before validateOneOff.
- Reject rows whose fire_at cannot be parsed rather than passing them through.
Example fix
// before
validateOneOff({ kind: 'one_off', fireAt: row.fire_at }); // row.fire_at is a string -> throws
// after - coerce at the boundary
const fireAt = new Date(row.fire_at as string);
if (Number.isNaN(fireAt.getTime())) {
throw new Error(`row ${row.id} has unparseable fire_at`);
}
validateOneOff({ kind: 'one_off', fireAt }); Defensive patterns
Strategy: type-guard
Validate before calling
function coerceFireAt(raw: unknown): Date {
const d = raw instanceof Date ? raw : new Date(raw as string);
if (!(d instanceof Date) || Number.isNaN(d.getTime())) {
throw new Error('fireAt must be a valid Date or ISO string');
}
return d;
}
validateOneOff({ kind: 'one_off', fireAt: coerceFireAt(row.fire_at) }); Type guard
function isValidFireAt(v: unknown): v is Date {
return v instanceof Date && !Number.isNaN(v.getTime());
} Prevention
- Configure the ORM/driver to return TIMESTAMP columns as Date (TypeORM timestamp -> Date).
- When deserializing JSON, wrap string timestamps with new Date(...) at the boundary.
- Reject Invalid Date at the controller before it reaches the scheduler.
- Never pass epoch numbers (Date.now()) where a Date is required - wrap them.
When it happens
Trigger: A one_off schedule loaded from a DB row where fire_at came back as a string (ORM not configured for Date), a number (epoch ms), null, or an Invalid Date from new Date('invalid'). Also a literal constructed with fireAt: '2025-01-01'.
Common situations: An ORM/driver that returns TIMESTAMP as ISO string unless explicitly mapped; JSON-deserialized input (JSON.parse yields string, not Date); new Date(undefined) producing Invalid Date; a test fixture that set fireAt: Date.now() (number) instead of new Date().
Related errors
- ${schedule.kind}.cronExpression must be a string, got ${JSON
- isBetween(): expected exactly two args
- Unsupported unit '${String(errorUnit)}'. Supported: ${durati
- Unsupported format '${String(valueFormat)}'. toDateTime() su
- Value is not a valid date
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/e9dae409ed80720a.
Report an issue: GitHub.