You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cloudflare Workflow teardown can deadlock on instrumented waitUntil #23005
instrumentWorkflowWithSentry captures context.waitUntil.bind(context) inside each run() call. init() instruments that same context. When Cloudflare reuses a Workflow instance, a later run can therefore capture Sentry’s flush-lock-aware waitUntil wrapper instead of the original function.
At the end of that run, the wrapper schedules flushAndDispose(client) through the captured function. This can register the teardown promise in the same flush lock that client.flush() is waiting to drain, so teardown never settles. In production this surfaced as Worker code had hung immediately after otherwise successful workflow completion.
Application work registered through the instrumented waitUntil should remain tracked; only Sentry’s own teardown must bypass its instrumentation.
Suggested fix
Capture the original function before client initialization, matching the existing RPC wrapper:
The CommonJS build can use the corresponding flush.getOriginalWaitUntil(context) export.
Regression shape
A regression test can reuse one instrumented Workflow instance for two runs. During the second run, register controlled pending application work through the instrumented context, return successfully, then release that work and await both the application and teardown promises. With the current implementation the teardown promise remains pending; using getOriginalWaitUntil lets both settle while genuine workflow errors still propagate.
Reopening with follow-up evidence. The runtime change from #23017 (getOriginalWaitUntil(context)) is present in our @sentry/cloudflare 10.69.0 patch, but staging still produced the same cancellation after a successful workflow: workflow_complete at 15:02:11.150Z; finalization outcome at 15:02:11.572Z; wrapper SUCCESS at 15:02:11.587Z; runtime cancellation at 15:02:13.572Z (~1.985s later, matching the 2s Sentry flush timeout). This suggests the remaining issue is post-run Sentry teardown via waitUntil rather than the reused-context deadlock. We are testing awaiting flushAndDispose(client) before the workflow run returns.
Activity
linear-code commentedon Aug 4, 2026
JS-3270
JPeer264 commentedon Aug 4, 2026
Thanks for raising this issue. It seems that we forgot to add the
getOriginalWaitUntilfor the workflows. I'll draft something and get a fix outfix(cloudflare): Get original waituntil in workflows (#23017)
matthew-gizmo commentedon Aug 6, 2026
Reopening with follow-up evidence. The runtime change from #23017 (getOriginalWaitUntil(context)) is present in our @sentry/cloudflare 10.69.0 patch, but staging still produced the same cancellation after a successful workflow: workflow_complete at 15:02:11.150Z; finalization outcome at 15:02:11.572Z; wrapper SUCCESS at 15:02:11.587Z; runtime cancellation at 15:02:13.572Z (~1.985s later, matching the 2s Sentry flush timeout). This suggests the remaining issue is post-run Sentry teardown via waitUntil rather than the reused-context deadlock. We are testing awaiting flushAndDispose(client) before the workflow run returns.
JPeer264 commentedon Aug 7, 2026
Thanks a lot for this follow-up. For my understanding and to include some proper tests for this, to you have a minimal repro for this?
Since it is based on the teardown #23083 could potentially solve that for good.
matthew-gizmo commentedon Aug 7, 2026
This isn't your bug now, I assumed it was but after debugging it's a bug in the cloudflare runtime with
waitForEventcloudflare/workerd#6925
Thanks for your help!