feat(node): Include global scope for eventLoopBlockIntegration#20108
feat(node): Include global scope for eventLoopBlockIntegration#20108
eventLoopBlockIntegration#20108Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Deps
Other
Bug Fixes 🐛
Internal Changes 🔧Core
Deps
Other
🤖 This preview updates automatically when you update the PR. |
size-limit report 📦
|
eventLoopBlockIntegrationeventLoopBlockIntegration
| const globalScope = getGlobalScope().getScopeData(); | ||
| const currentScope = getCurrentScope().getScopeData(); | ||
| mergeScopeData(globalScope, currentScope); |
There was a problem hiding this comment.
Is this required of can we just sync the global scope?
There was a problem hiding this comment.
this seems reasonable to me? ideally I guess it should be global + isolation + current scope, not sure if/how isolation scope is handled here generally :)
There was a problem hiding this comment.
Isolation scope is captured via native code from the AsyncLocalStorage!
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: ScopeData with non-serializable fields passed to native module
- Added getSerializableScopeData() function to strip non-serializable fields (eventProcessors, span, attachments) from ScopeData before passing to threadPoll() for cross-thread serialization.
Or push these changes by commenting:
@cursor push 24ad4e1753
Preview (24ad4e1753)
diff --git a/packages/node-native/src/common.ts b/packages/node-native/src/common.ts
--- a/packages/node-native/src/common.ts
+++ b/packages/node-native/src/common.ts
@@ -40,6 +40,6 @@
export interface ThreadState {
session: Session | undefined;
- scope: ScopeData;
+ scope: Partial<ScopeData>;
debugImages: Record<string, string>;
}
diff --git a/packages/node-native/src/event-loop-block-integration.ts b/packages/node-native/src/event-loop-block-integration.ts
--- a/packages/node-native/src/event-loop-block-integration.ts
+++ b/packages/node-native/src/event-loop-block-integration.ts
@@ -54,6 +54,24 @@
return globalScope;
}
+/**
+ * Extracts only the serializable fields from ScopeData that can be passed to the native module.
+ * Removes non-serializable fields like eventProcessors (functions), span (complex object), and attachments.
+ */
+function getSerializableScopeData(scopeData: ScopeData): Partial<ScopeData> {
+ return {
+ tags: scopeData.tags,
+ attributes: scopeData.attributes,
+ extra: scopeData.extra,
+ user: scopeData.user,
+ contexts: scopeData.contexts,
+ level: scopeData.level,
+ fingerprint: scopeData.fingerprint,
+ propagationContext: scopeData.propagationContext,
+ conversationId: scopeData.conversationId,
+ };
+}
+
type IntegrationInternal = { start: () => void; stop: () => void };
function poll(enabled: boolean, clientOptions: ClientOptions): void {
@@ -62,7 +80,9 @@
// We need to copy the session object and remove the toJSON method so it can be sent to the worker
// serialized without making it a SerializedSession
const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;
- const scope = getLocalScopeData();
+ const scopeData = getLocalScopeData();
+ // Strip non-serializable fields from scope data before passing to native module
+ const scope = getSerializableScopeData(scopeData);
// message the worker to tell it the main event loop is still running
threadPoll(enabled, { session, scope, debugImages: getFilenameToDebugIdMap(clientOptions.stackParser) });
} catch {This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0742247. Configure here.
| const currentScope = getCurrentScope().getScopeData(); | ||
| mergeScopeData(globalScope, currentScope); | ||
| return globalScope; | ||
| } |
There was a problem hiding this comment.
ScopeData with non-serializable fields passed to native module
Medium Severity
getLocalScopeData() returns a full ScopeData object containing eventProcessors (an array of functions) and potentially span (a complex object with methods). This is passed to threadPoll which needs to share data cross-thread via the native module. The existing code already carefully strips the non-serializable toJSON method from session objects before passing them to threadPoll, but no similar care is taken for ScopeData. If event processors are registered on the global or current scope, the non-serializable functions could cause the threadPoll call to fail, with the error silently swallowed by the try/catch, losing all scope data.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 0742247. Configure here.
There was a problem hiding this comment.
ScopeData doesn't contain any of those and is safe to serialise...



Global scope is not captured by the native module through the
AsyncLocalStorageso this PR sends that via the polling mechanism.