anomalyco/sst · error · TypeError
waitUntil requires a valid Date
Error message
waitUntil requires a valid Date
What it means
resolveWaitUntilDuration converts a Date passed to durable workflow waitUntil() into a Duration. It throws a TypeError when Date.getTime() returns NaN/Infinity, i.e. the argument is not a valid Date. This guards against scheduling a wait on an unusable timestamp.
Source
Thrown at sdk/js/src/aws/workflow.ts:797
: parseTimestamp(execution.EndTimestamp),
};
}
function parseTimestamp(timestamp: string | number): Date {
const value =
typeof timestamp === "number" ? timestamp : Number(timestamp);
if (Number.isFinite(value)) {
return new Date(value < 1_000_000_000_000 ? value * 1000 : value);
}
return new Date(timestamp);
}
function resolveWaitUntilDuration(until: Date): durable.Duration {
const timestamp = until.getTime();
if (!Number.isFinite(timestamp)) {
throw new TypeError("waitUntil requires a valid Date");
}
return {
seconds: Math.max(0, Math.ceil((timestamp - Date.now()) / 1000)),
};
}
function withRollback<
TLogger extends durable.DurableLogger = durable.DurableLogger,
>(context: durable.DurableContext<TLogger>): workflow.Context<TLogger> {
const wrapped = context as WrappedDurableContext<TLogger>;
if (wrapped[rollbackStateSymbol]) return wrapped as workflow.Context<TLogger>;
const rollbackState: RollbackState<TLogger> = { undoStack: [] };
wrapped[rollbackStateSymbol] = rollbackState;
Object.defineProperty(wrapped, "stepWithRollback", {View on GitHub (pinned to a0bd20f762)
Solutions
- Check the Date before passing it: Number.isFinite(date.getTime()) must be true.
- Trace where the Date is constructed — usually an upstream parse of missing or malformed data.
- Provide a fallback deadline (e.g. now + default timeout) when the source value is absent.
- Log the offending value to confirm it is Invalid Date and fix the parsing/format at the source.
Example fix
// before
const deadline = new Date(config.deadline);
await workflow.waitUntil(deadline);
// after
const deadline = new Date(config.deadline);
if (Number.isNaN(deadline.getTime())) {
deadline.setTime(Date.now() + 60_000); // fallback: 1 minute from now
}
await workflow.waitUntil(deadline); Defensive patterns
Strategy: validation
Validate before calling
export function assertValidDate(d: Date): Date {
if (!(d instanceof Date) || !Number.isFinite(d.getTime())) {
throw new TypeError(`waitUntil requires a valid Date, got ${d}`);
}
return d;
}
// usage: await workflow.waitUntil(assertValidDate(deadline)); Type guard
function isValidDate(value: unknown): value is Date {
return value instanceof Date && Number.isFinite(value.getTime());
} Try / catch
try {
await workflow.waitUntil(deadline);
} catch (e) {
if (e instanceof TypeError && /valid Date/.test(e.message)) {
await workflow.waitUntil(new Date(Date.now() + 60_000)); // fallback
} else throw e;
} Prevention
- Validate Dates at the boundary where they are parsed from external input.
- Never construct Dates from possibly-undefined values without a fallback.
- Use isValidDate() before any time-based workflow API.
- Prefer numeric epoch inputs (validated with Number.isFinite) over string parsing.
When it happens
Trigger: Calling waitUntil() with an invalid Date — e.g. new Date(undefined), new Date("not-a-date"), a Date parsed from missing/malformed input — so until.getTime() is not finite.
Common situations: Parsing a deadline from an optional API field or environment variable that came back undefined or in an unexpected format; arithmetic like new Date(Date.parse(badString)); passing a non-Date value that was cast to Date.
Related errors
- Invalid size ${size}
- Lifecycle rule at index ${index} has an empty or whitespace-
- You cannot provide both "job" and "function" in the "${name}
- You cannot provide both a function and a task in the "${name
- You must provide either a function or a task in the "${name}
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/64dd944fe08d119b.
Report an issue: GitHub.