Repository navigation
Description
Is there an existing issue for this?
- I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
- I have reviewed the documentation https://docs.sentry.io/
- I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/cloudflare
SDK Version
11.12.0 (the code is the same on develop)
Framework Version
wrangler 4.156.0, compatibility_date 2026-05-01, compatibility_flags ["nodejs_compat"]
Reproduction Example/SDK Setup
import * as Sentry from '@sentry/cloudflare'
import { WorkflowEntrypoint } from 'cloudflare:workers'
import { NonRetryableError } from 'cloudflare:workflows'
class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
async run(event, step) {
if (!event.payload.accountId) {
throw new NonRetryableError('accountId is required')
}
await step.do('load', { timeout: '1 second' }, async () => {
// ...
})
}
}
export const Instrumented = Sentry.instrumentWorkflowWithSentry(
(env) => ({ dsn: env.SENTRY_DSN }),
MyWorkflow,
)Steps to Reproduce
- Wrap a Workflow with
instrumentWorkflowWithSentry. - Let
run()fail outside a step callback, for example by throwing before the first step or by a step timeout. - Trigger an instance.
Expected Result
One Sentry event for the error that fails the instance.
Actual Result
No event. The instance fails and the error is only in the Workers logs.
dev-packages/cloudflare-integration-tests on develop, one instance per row, retries.limit: 0 on steps:
run() fails with |
Sentry events |
|---|---|
TypeError thrown before any step |
0 |
NonRetryableError thrown before any step |
0 |
Error thrown after a successful step |
0 |
step.waitForEvent timeout |
0 |
step.do timeout (Execution timed out after 1000ms) |
0 |
step.do returning a non-serializable value (Aborting engine: Value is not serialisable) |
0 |
Error thrown inside the step.do callback |
1 |
The run proxy in instrumentWorkflowWithSentry wraps the call in try { … } finally { waitUntil(flushAndDispose(client)) } with no catch. Only WrappedWorkflowStep.do calls captureException, and only when the callback itself throws.
Additional Context
Cloudflare docs: "Any error not handled at this top level will cause the Workflow instance to fail."
A catch in the run proxy alone is not enough: step.do rejects with a copy of the error the callback threw, so the __sentry_captured__ mark does not carry over and every failed step is reported twice. The fix tracks, per step.do call, whether the step callback already captured the error, and run skips only those rejections. Step timeouts and engine-side step failures are still reported once by run.
Contribution
I have this fix ready with unit tests and integration tests covering the cases in the table above, and can open a PR once you give the go-ahead.
Metadata
Metadata
Assignees
Projects
- StatusShow more project fieldsWaiting for: Product Owner
Activity
linear-code commentedon Nov 11, 2026
JS-4097