-
- Notifications
You must be signed in to change notification settings - Fork 1.7k
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
10.30.0
Framework Version
Cloudflare Workers (Durable Objects)
Link to Sentry event
No events are being sent - that's the issue
Reproduction Example/SDK Setup
// packages/signal/src/index.ts import * as Sentry from '@sentry/cloudflare'; Sentry.init({ dsn: 'https://xxx@xxx.ingest.us.sentry.io/xxx', tracesSampleRate: 1.0, environment: 'production', }); export default instrumentDurableObjectWithSentry(TradingAgent, { dsn: 'https://xxx@xxx.ingest.us.sentry.io/xxx', tracesSampleRate: 1.0, });Steps to Reproduce
- Set up @sentry/cloudflare in a Cloudflare Worker or Durable Object
- Configure Sentry with valid DSN
- Trigger any Sentry event (error, message, etc.)
- Monitor Worker logs with
wrangler tail - Observe warnings:
"(warn) A stalled HTTP response was canceled to prevent deadlock..."
Expected Result
- Sentry events should be successfully transmitted to Sentry servers
- No "stalled HTTP response" warnings in logs
- Events should appear in Sentry dashboard
Actual Result
Console logs work correctly (visible in wrangler tail), but Sentry events never reach the server.
Logs show repeated warnings:
(warn) A stalled HTTP response was canceled to prevent deadlock. This can happen when a Worker calls fetch() or cache.match() several times without reading the bodies of the returned Response objects. Root Cause
The Cloudflare transport implementation at packages/cloudflare/src/transport.ts performs a fetch() to send events but never consumes the response body.
Cloudflare Workers runtime requires ALL fetch response bodies to be either:
- Read via
response.text(),response.json(),response.arrayBuffer(), etc. - Explicitly canceled via
response.body?.cancel()
Otherwise, the runtime cancels stalled HTTP connections to prevent deadlock.
Problematic code pattern:
const response = await (options.fetch ?? fetch)(options.url, requestOptions); return { statusCode: response.status, headers: { 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'), 'retry-after': response.headers.get('Retry-After'), }, }; // ❌ response.body is never consumed!Suggested Fix
Add response body consumption after the fetch:
const response = await (options.fetch ?? fetch)(options.url, requestOptions); // Consume the response body to prevent Cloudflare from canceling the request // We don't need the body content, but we must read or cancel it await response.text().catch(() => {}); // or response.body?.cancel() return { statusCode: response.status, headers: { 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'), 'retry-after': response.headers.get('Retry-After'), }, };Additional Context
This issue affects all Cloudflare Workers deployments using @sentry/cloudflare, including:
- Cloudflare Workers
- Cloudflare Durable Objects
- Cloudflare Pages Functions
The problem is specific to the Cloudflare Workers runtime, which enforces stricter fetch response handling than browser or Node.js environments.
Workaround: Currently using wrangler tail for live logging instead of Sentry event transmission.
Related Cloudflare Documentation:
- Workers fetch API best practices
- Cloudflare explicitly warns about unconsumed response bodies causing connection cancellations
Priority
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it.
Metadata
Metadata
Assignees
Projects
Status