Skip to content

Commit 583c991

Browse files
antonisclaude
andcommitted
fix: Also handle stack with no frames (message-only stack string)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bc7535c commit 583c991

2 files changed

Lines changed: 34 additions & 4 deletions

File tree

packages/core/src/js/integrations/reactnativeerrorhandlers.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,12 @@ function setupErrorUtilsGlobalHandler(): void {
170170
return;
171171
}
172172

173-
// React render errors may arrive without a .stack but with a .componentStack
174-
// (set by ReactFiberErrorDialog). Use the componentStack as a fallback so
173+
// React render errors may arrive without useful frames in .stack but with a
174+
// .componentStack (set by ReactFiberErrorDialog) that contains component
175+
// locations with bundle offsets. Use componentStack as a fallback so
175176
// eventFromException can extract frames with source locations.
176177
// oxlint-disable-next-line typescript-eslint(no-unsafe-member-access)
177-
if (!error.stack && error.componentStack) {
178+
if (error.componentStack && (!error.stack || !hasStackFrames(error.stack))) {
178179
// oxlint-disable-next-line typescript-eslint(no-unsafe-member-access)
179180
error.stack = `${error.message || 'Error'}${error.componentStack}`;
180181
}
@@ -220,3 +221,10 @@ function setupErrorUtilsGlobalHandler(): void {
220221
);
221222
});
222223
}
224+
225+
/**
226+
* Checks if a stack trace string contains at least one frame line.
227+
*/
228+
function hasStackFrames(stack: unknown): boolean {
229+
return typeof stack === 'string' && stack.includes('\n');
230+
}

packages/core/test/integrations/reactnativeerrorhandlers.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,29 @@ describe('ReactNativeErrorHandlers', () => {
162162
);
163163
});
164164

165-
test('Does not override stack when error already has one', async () => {
165+
test('Uses componentStack as fallback when stack has no frames', async () => {
166+
const integration = reactNativeErrorHandlersIntegration();
167+
integration.setupOnce!();
168+
169+
const error: any = {
170+
message: 'Value is undefined, expected an Object',
171+
stack: 'Error: Value is undefined, expected an Object',
172+
componentStack:
173+
'\n at UserMessage (http://localhost:8081/index.bundle:1:5274251)' +
174+
'\n at renderItem (http://localhost:8081/index.bundle:1:5280705)',
175+
};
176+
177+
await errorHandlerCallback!(error, true);
178+
await client.flush();
179+
180+
expect(error.stack).toBe(
181+
'Value is undefined, expected an Object' +
182+
'\n at UserMessage (http://localhost:8081/index.bundle:1:5274251)' +
183+
'\n at renderItem (http://localhost:8081/index.bundle:1:5280705)',
184+
);
185+
});
186+
187+
test('Does not override stack when error already has frames', async () => {
166188
const integration = reactNativeErrorHandlersIntegration();
167189
integration.setupOnce!();
168190

0 commit comments

Comments
 (0)