{"record":{"id":"64dd944fe08d119b","repo":"anomalyco/sst","slug":"waituntil-requires-a-valid-date","errorCode":null,"errorMessage":"waitUntil requires a valid Date","messagePattern":"waitUntil requires a valid Date","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdk/js/src/aws/workflow.ts","lineNumber":797,"sourceCode":"        : parseTimestamp(execution.EndTimestamp),\n  };\n}\n\nfunction parseTimestamp(timestamp: string | number): Date {\n  const value =\n    typeof timestamp === \"number\" ? timestamp : Number(timestamp);\n\n  if (Number.isFinite(value)) {\n    return new Date(value < 1_000_000_000_000 ? value * 1000 : value);\n  }\n\n  return new Date(timestamp);\n}\n\nfunction resolveWaitUntilDuration(until: Date): durable.Duration {\n  const timestamp = until.getTime();\n  if (!Number.isFinite(timestamp)) {\n    throw new TypeError(\"waitUntil requires a valid Date\");\n  }\n\n  return {\n    seconds: Math.max(0, Math.ceil((timestamp - Date.now()) / 1000)),\n  };\n}\n\nfunction withRollback<\n  TLogger extends durable.DurableLogger = durable.DurableLogger,\n>(context: durable.DurableContext<TLogger>): workflow.Context<TLogger> {\n  const wrapped = context as WrappedDurableContext<TLogger>;\n  if (wrapped[rollbackStateSymbol]) return wrapped as workflow.Context<TLogger>;\n\n  const rollbackState: RollbackState<TLogger> = { undoStack: [] };\n\n  wrapped[rollbackStateSymbol] = rollbackState;\n\n  Object.defineProperty(wrapped, \"stepWithRollback\", {","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/sdk/js/src/aws/workflow.ts#L779-L815","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst deadline = new Date(config.deadline);\nawait workflow.waitUntil(deadline);\n\n// after\nconst deadline = new Date(config.deadline);\nif (Number.isNaN(deadline.getTime())) {\n  deadline.setTime(Date.now() + 60_000); // fallback: 1 minute from now\n}\nawait workflow.waitUntil(deadline);","handlingStrategy":"validation","validationCode":"export function assertValidDate(d: Date): Date {\n  if (!(d instanceof Date) || !Number.isFinite(d.getTime())) {\n    throw new TypeError(`waitUntil requires a valid Date, got ${d}`);\n  }\n  return d;\n}\n// usage: await workflow.waitUntil(assertValidDate(deadline));","typeGuard":"function isValidDate(value: unknown): value is Date {\n  return value instanceof Date && Number.isFinite(value.getTime());\n}","tryCatchPattern":"try {\n  await workflow.waitUntil(deadline);\n} catch (e) {\n  if (e instanceof TypeError && /valid Date/.test(e.message)) {\n    await workflow.waitUntil(new Date(Date.now() + 60_000)); // fallback\n  } else throw e;\n}","preventionTips":["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."],"tags":["typescript","validation","workflow","invalid-date"],"backgroundTag":"invalid-date-argument","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}