Skip to content

🐛 Workflows: caught waitForEvent timeout emits false "Worker code had hung" cancellation #6925

Description

@matthew-gizmo

Summary

A standalone deployed Workflow reproduces a Workers runtime cancellation after a waitForEvent() timeout is caught and the Workflow run() method reaches its end. The HTTP API request succeeds, but the Workflow invocation is logged as:

The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response.

The repro has no Sentry, RPC, queues, Durable Objects, waitUntil(), or application imports.

Reproduction

Deployed repro:

https://workflow-timeout-repro.gizmo-ai.workers.dev

  1. Run the timeout case:
curl 'https://workflow-timeout-repro.gizmo-ai.workers.dev/?mode=timeout'
  1. The request returns HTTP 200 with a Workflow instance ID.
  2. The Workflow waits for an event with a one-second timeout. No event is sent.
  3. The timeout is caught, the Workflow logs repro timeout caught, then logs repro workflow finished.
  4. The Workers logs then contain the cancellation above.

For comparison, this case sends the matching event after 100 ms and completes without the cancellation:

curl 'https://workflow-timeout-repro.gizmo-ai.workers.dev/?mode=event'

Minimal repro

exportclassTimeoutWorkflowextendsWorkflowEntrypoint<Env,Params>{asyncrun(_event: WorkflowEvent<Params>,step: WorkflowStep): Promise<void>{try{awaitstep.waitForEvent('repro wait',{type: 'workflow-timeout-repro-event',timeout: '1 second',});console.log('repro event received');}catch(error){console.log('repro timeout caught',error);}console.log('repro workflow finished');}}

The fetch handler only creates the Workflow instance and returns JSON. The deployed worker is a standalone reproduction; its source can be provided privately if needed.

Expected behavior

Once the waitForEvent() timeout rejects, the rejection is caught and run() returns normally. The Workflow should complete without a runtime hung-request cancellation.

Environment

  • Deployed Worker: workflow-timeout-repro
  • Compatibility date: 2026-08-06
  • Cloudflare Workflows on Workers
  • Reproduces on the deployed runtime; the event-success path is clean

Could this be a timeout-cleanup issue where waitForEvent() leaves a pending resolver, event listener, or other promise associated with the Workflow invocation after its timeout has been caught?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions