Skip to content

Conversation

@hrynevychroman
Copy link

We receive this date as string so we need to parse it

Fix #340

@changeset-bot
Copy link

changeset-bot bot commented Nov 14, 2025

⚠️ No Changeset found

Latest commit: 593c706

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link
Contributor

vercel bot commented Nov 14, 2025

@hrynevychroman is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

When events are deserialized from the backend, the resumeAt date field is returned as a string, but sleep.ts assigns this directly to waitItem.resumeAt which expects a Date object. This causes a TypeError later when runtime.ts tries to call .getTime() on the string value.

View Details
📝 Patch Details
diff --git a/packages/core/src/workflow/sleep.ts b/packages/core/src/workflow/sleep.ts
index 0b16fd3..1edbf9f 100644
--- a/packages/core/src/workflow/sleep.ts
+++ b/packages/core/src/workflow/sleep.ts
@@ -44,7 +44,9 @@ export function createSleep(ctx: WorkflowOrchestratorContext) {
         ) as WaitInvocationQueueItem | undefined;
         if (waitItem) {
           waitItem.hasCreatedEvent = true;
-          waitItem.resumeAt = event.eventData.resumeAt;
+          waitItem.resumeAt = event.eventData.resumeAt
+            ? new Date(event.eventData.resumeAt)
+            : event.eventData.resumeAt;
         }
         return EventConsumerResult.Consumed;
       }

Analysis

Type mismatch: resumeAt string assigned to Date-typed field causes runtime error

What fails: When a wait_created event is received in sleep.ts line 47, the resumeAt field from the deserialized event data (which is a string from JSON) is directly assigned to waitItem.resumeAt (which is typed as Date). This causes a TypeError: resumeAt.getTime is not a function later when runtime.ts line 487 tries to call .getTime() on the value.

How to reproduce:

  1. Create a workflow that calls sleep()
  2. The workflow gets suspended and creates a wait_created event
  3. The event is fetched from the backend and deserialized (date fields become strings in JSON)
  4. When the wait_created event callback executes in sleep.ts, it assigns the string to waitItem.resumeAt
  5. On next execution, runtime.ts line 487 attempts queueItem.resumeAt.getTime() and throws

Result: TypeError: resumeAt.getTime is not a function when processing wait queue items

Expected: The resumeAt field should always be a Date object, matching the type contract defined in WaitInvocationQueueItem (global.ts line 19)

Root cause: When events are deserialized from backend storage (JSON), date strings remain as strings rather than being automatically converted to Date objects. The fix in runtime.ts lines 343-345 converts these strings to Dates for runtime processing, but the same conversion was missing in sleep.ts where the deserialized event data is assigned to the queue item.

Fix applied: Wrapped the assignment in sleep.ts line 47-49 with a new Date() conversion, matching the pattern used in runtime.ts lines 343-345.

Fix on Vercel

Copy link
Collaborator

@pranaygp pranaygp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment below.

I do think we also really need to include e2e tests for the postgres world. That would've prevented an issue like this

for (const event of events) {
if (event.eventType === 'wait_created') {
const resumeAt = event.eventData.resumeAt as Date;
const resumeAt = event.eventData.resumeAt
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the world should return resumeAt as a date - so if this is working in vercel and local worlds, this this looks like a postgres world implementation issue. The real fix is postgres world should match the interface and return a date

The zod return type for resumeAt is already meant to be a date:

https://github.com/vercel/workflow/blob/main/packages/world/src/events.ts#L82-L82

@pranaygp
Copy link
Collaborator

fyi I've added postgres world e2e tests now in #356

It seems we have a couple of postgres e2e tests that are failing on different workbenches that need work:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgresError: column "retry_after" of relation "workflow_steps" does not exist

2 participants