-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Environment
@sentry/cloudflareversion: 10.41.0 (regression from 10.40.0)- Cloudflare Workers runtime with
WorkerEntrypointRPC (service bindings) - Uses
withSentry()wrapper for the default export, andWorkerEntrypointclasses exported separately
Description
After upgrading from @sentry/cloudflare 10.40.0 to 10.41.0, we get TypeError: Cannot read properties of undefined (reading 'add') when RPC methods on WorkerEntrypoint classes use Sentry tracing (e.g., startSpan, continueTrace).
Root Cause
10.41.0 introduced flushAndDispose() which replaces flush(2000) in all request completion paths (request.js, handler.js, wrapMethodWithSentry.js). The new ServerRuntimeClient.dispose() sets this._promiseBuffer = undefined. When a WorkerEntrypoint RPC method later tries to use Sentry tracing, it encounters the disposed client and crashes on _promiseBuffer.add().
The mechanism
- Worker handles a
fetchrequest viawithSentry()→ Sentry client is created - Request completes →
flushAndDispose(client)runs →dispose()sets_promiseBuffer = undefined - An RPC call arrives at a
WorkerEntrypointmethod (e.g.,SessionsRpc.validateSession) WorkerEntrypointmethods are not wrapped bywithSentry()— they are separate exports- The RPC handler uses Sentry tracing (
startSpan,continueTrace) which creates a span - When the span ends, the SDK calls
captureEvent()→_process()→_promiseBuffer.add() - Crash:
_promiseBufferisundefinedbecause the client was disposed
Why this worked in 10.40.0
In 10.40.0, flush(2000) was called at request completion — the client remained fully functional with all internal state intact. There was no dispose() method, no flushAndDispose() helper, and _promiseBuffer was never set to undefined.
Reproduction
// Worker entry (auth.ts)
import { withSentry } from './sentry-config';
import { SessionsRpc } from './sessions.rpc';
const app = new Hono();
// ... routes ...
// Default export wrapped with Sentry
export default withSentry({ fetch: app.fetch.bind(app) }, 'auth-worker');
// WorkerEntrypoint exported separately — NOT wrapped by withSentry
export { SessionsRpc };// sessions.rpc.ts
import { WorkerEntrypoint } from 'cloudflare:workers';
import * as Sentry from '@sentry/cloudflare';
export class SessionsRpc extends WorkerEntrypoint {
async validateSession(ctx, request) {
// This crashes with "Cannot read properties of undefined (reading 'add')"
// because the Sentry client was disposed after the last fetch request
return Sentry.startSpan({ name: 'validateSession' }, async () => {
// ... session validation logic ...
});
}
}Workaround
Pin @sentry/cloudflare to 10.40.0.
Suggested Fix
The flushAndDispose pattern is fundamentally incompatible with the Cloudflare Workers model where:
- The same isolate handles both
fetchrequests andWorkerEntrypointRPC calls - RPC calls don't go through
withSentry/wrapRequestHandler - A disposed client may still be referenced by subsequent operations
Possible solutions:
- Don't
dispose()the client in Workers — useflush()only (revert to 10.40.0 behavior) - Add a guard in
_process()to check if_promiseBufferexists before calling.add() - Mark disposed clients so that
getClient()returnsundefinedfor them, preventing use
Diff evidence
# @sentry/core server-runtime-client.js (10.40.0 → 10.41.0)
+ dispose() {
+ for (const hookName of Object.keys(this._hooks)) {
+ this._hooks[hookName]?.clear();
+ }
+ this._hooks = {};
+ this._eventProcessors.length = 0;
+ this._integrations = {};
+ this._outcomes = {};
+ (this)._transport = undefined;
+ (this)._promiseBuffer = undefined; // <-- THIS CAUSES THE CRASH
+ }
# @sentry/cloudflare request.js (10.40.0 → 10.41.0)
- waitUntil?.(flush(2000));
+ waitUntil?.(flushAndDispose(client));Metadata
Metadata
Assignees
Labels
Projects
Status