vercel / vercel/next.js

AppRender.fetch spans never set span status to ERROR for failed (4xx/5xx) responses

Open Beginner friendly
#94,901 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Instrumentation
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
  1. git clone https://github.com/anilparlak/otel-repro && cd otel-repro
  2. npm install
  3. npm run dev
  4. In another terminal: curl http://localhost:3000/
  5. In the dev-server console, look at the fetch GET .../api/fail span:
    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_code convention
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.