Skip to content

Commit eb60783

Browse files
fix(solidstart): Read server action route from the request's root span (#25513)
This fixes the `E2E solidstart-2` failure on `develop`. Since #25295, the "sends a server action span on client navigation" test times out because the `POST getPrefecture` segment is never sent. _Root cause:_ After #25295, Nitro's h3 route handler opens a `handler` span instead of a nested `http.server` span. `withServerActionInstrumentation` decided whether to rename the segment by reading the attributes of the *active* span. Now that span is the `handler` span, which has no `url.path`, so the `/_server` check never matched and the server action name was never applied. The fix reads the attributes from the root span instead. That is the request's `http.server` span, the one `setHttpServerSpanRouteAttribute` renames, so the check and the rename now target the same span whatever the framework nests in between. Locally, `solidstart-2` E2E fails 1/9 (this test) without the change and passes 9/9 with it. <!-- junior-request-attribution:start --> via **Francesco Gringl-Novy**. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent-dispatch%3Adispatch_6234d76cd131dcc5f1925dab1ce334ad --> -- [View Junior Session](https://junior-prod.sentry.dev/conversations/agent-dispatch%3Adispatch_6234d76cd131dcc5f1925dab1ce334ad) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent-dispatch%3Adispatch_6234d76cd131dcc5f1925dab1ce334ad/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: Francesco Gringl-Novy <francesco.novy@sentry.io>
1 parent b151d07 commit eb60783

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

‎packages/solidstart/src/server/withServerActionInstrumentation.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { handleCallbackErrors, SPAN_STATUS_ERROR } from '@sentry/core';
22
import { flushIfServerless } from '@sentry/core/server';
3-
import { captureException, getActiveSpan, spanToJSON, startSpan } from '@sentry/node';
3+
import { captureException, getActiveSpan, getRootSpan, spanToJSON, startSpan } from '@sentry/node';
44
import { isRedirect } from './utils';
55
import {
66
SENTRY_SEGMENT_NAME_SOURCE,
@@ -25,7 +25,9 @@ export async function withServerActionInstrumentation<A extends (...args: unknow
2525
const activeSpan = getActiveSpan();
2626

2727
if (activeSpan) {
28-
const spanData = spanToJSON(activeSpan).attributes;
28+
// Read the request's `http.server` root span, which is the span we rename. The active span is
29+
// usually a framework handler span (e.g. Nitro's h3 `handler` span) without any URL attributes.
30+
const spanData = spanToJSON(getRootSpan(activeSpan)).attributes;
2931

3032
// In solid start, server function calls are made to `/_server` which doesn't tell us
3133
// a lot. We rewrite the span's route to be that of the sever action name but only

‎packages/solidstart/test/server/withServerActionInstrumentation.test.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,28 @@ describe('withServerActionInstrumentation', () => {
169169
expect(mockSpanSetAttribute).to.toHaveBeenCalledWith(SENTRY_SEGMENT_NAME_SOURCE, 'route');
170170
});
171171

172+
it('sets a server action name on the root span when the active span is a nested handler span', async () => {
173+
const rootSpan = new SentryCore.SentrySpan({
174+
attributes: {
175+
'url.path': '/_server',
176+
[SENTRY_OP]: 'http.server',
177+
},
178+
});
179+
const handlerSpan = new SentryCore.SentrySpan({
180+
attributes: {
181+
[SENTRY_OP]: 'handler',
182+
},
183+
});
184+
SentryCore.addChildSpanToSpan(rootSpan, handlerSpan);
185+
mockGetActiveSpan.mockReturnValue(handlerSpan);
186+
const mockRootSpanSetAttribute = vi.spyOn(rootSpan, 'setAttribute');
187+
188+
await serverActionGetPrefecture();
189+
190+
expect(mockRootSpanSetAttribute).toHaveBeenCalledWith('http.route', 'getPrefecture');
191+
expect(mockRootSpanSetAttribute).toHaveBeenCalledWith(SENTRY_SEGMENT_NAME_SOURCE, 'route');
192+
});
193+
172194
it('does not set a server action name if the active span had a non `/_server` `url.path`', async () => {
173195
const span = new SentryCore.SentrySpan();
174196
span.setAttribute('url.path', '/users/5');

0 commit comments

Comments
 (0)