AppRender.fetch spans never set span status to ERROR for failed (4xx/5xx) responses
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.4k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/anilparlak/otel-repro/tree/main
To Reproduce
- git clone https://github.com/anilparlak/otel-repro && cd otel-repro
- npm install
- npm run dev
- In another terminal: curl http://localhost:3000/
- In the dev-server console, look at the
fetch GET .../api/failspan:
despite the upstream HTTP 503, it has status: { code: 0 } (UNSET).
Notes:
- To test 4xx, change the status in app/api/fail/route.ts to 404.
- To see the @vercel/otel path, swap instrumentation.ts with
instrumentation.vercel.ts (the README documents both variants).
Current vs. Expected behavior
Current behavior
Next.js's native fetch instrumentation (patch-fetch.ts) creates
AppRender.fetch spans but never calls
span.setStatus({ code: SpanStatusCode.ERROR }) when the upstream response
status is 4xx/5xx. OTel-compatible APM backends (Azure Application Insights,
Datadog, Honeycomb, …) that consume these native spans therefore record
failed backend dependencies as successful.
Observed span status (Next 16 canary, @opentelemetry/sdk-trace-node 1.x):
| Path | Response | span.status.code |
|---|---|---|
| native (patch-fetch.ts) | 503 | 0 (UNSET) |
| native (patch-fetch.ts) | 404 | 0 (UNSET) |
| @vercel/otel | 503 | 2 (ERROR) |
| @vercel/otel | 404 | 0 (UNSET) |
The native path marks neither 4xx nor 5xx; @vercel/otel marks only
status >= 500, so 4xx is unmarked on every path.
Native-path span (503), abbreviated console output:
name: 'fetch GET .../api/fail',
attributes: {
'next.span_type': 'AppRender.fetch',
'http.method': 'GET',
...
},
status: { code: 0 }, // UNSET, despite the upstream HTTP 503
Concrete impact — Azure Application Insights
A server-side fetch returning HTTP 503 is recorded as a successful
dependency (resultCode 0, success True), with customDimensions showing
next.span_type: AppRender.fetch and no error status. In the APM UI the
Failures → Dependencies panel is empty, the Application Map shows a 0%
failure rate (looks healthy), and operators cannot diagnose backend errors
from the APM UI alone.
Expected behavior
For 4xx/5xx responses, the AppRender.fetch span should be marked with
SpanStatusCode.ERROR so APM backends record the dependency as failed.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 23.1.0: Mon Oct 9 21:32:52 PDT 2023; root:xnu-10002.41.9~7/RELEASE_ARM64_T8122
Available memory (MB): 16384
Available CPU cores: 8
Binaries:
Node: 22.21.1
npm: 10.9.4
Yarn: N/A
pnpm: N/A
Relevant Packages:
next: 16.3.0-canary.53 // Latest available version is detected (16.3.0-canary.53).
eslint-config-next: N/A
react: 19.0.0
react-dom: 19.0.0
typescript: 6.0.3
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Instrumentation
Which stage(s) are affected? (Select all that apply)
next dev (local)
Additional context
Related work
Two existing PRs add a status-code attribute but neither sets the span status to ERROR:
- #57646 — adds the deprecated
http.status_code - #84039 — uses the current
http.response.status_codeconvention
Suggested fix
In the same place the status-code attribute is set (packages/next/src/server/lib/patch-fetch.ts), also set the span status for failed responses (exact variable name may differ):
import { SpanStatusCode } from '@opentelemetry/api'
if (response.status >= 400) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: `HTTP ${response.status}`,
})
}
Note this affects next start (production) too, not just next dev.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/next/src/server/lib/patch-fetch.ts, at the existing status-code attribute handling, and run the linked otel-repro steps to observe the native AppRender.fetch span for 404 and 503 responses. Done means failed 4xx/5xx responses produce spans with SpanStatusCode.ERROR while preserving the existing instrumentation behavior, including next start.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nextjs, typescript
- Domain
- observability
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100