Skip to content

Multiple trace IDs generated in sentry-trace header when using Next.js #13870

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
3 tasks done
shlyamster opened this issue Oct 4, 2024 · 9 comments · Fixed by #13907
Closed
3 tasks done

Multiple trace IDs generated in sentry-trace header when using Next.js #13870

shlyamster opened this issue Oct 4, 2024 · 9 comments · Fixed by #13907
Labels
Package: nextjs Issues related to the Sentry Nextjs SDK

Comments

@shlyamster
Copy link

shlyamster commented Oct 4, 2024

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nextjs

SDK Version

8.33.1

Framework Version

Next 14.2.14

Link to Sentry event

n/a

Reproduction Example/SDK Setup

Dependencies

{
  "dependencies": {
    "@next/third-parties": "^14.2.14",
    "@nextui-org/react": "2.4.2",
    "@nextui-org/use-infinite-scroll": "^2.1.5",
    "@nimpl/middleware-chain": "^0.4.0",
    "@sentry/nextjs": "^8.33.1",
    "caniuse-lite": "^1.0.30001667",
    "clsx": "^2.1.1",
    "dayjs": "^1.11.13",
    "framer-motion": "^11.11.0",
    "intl-locale-textinfo-polyfill": "^2.1.1",
    "negotiator": "^0.6.3",
    "next": "^14.2.14",
    "next-mdx-remote": "^5.0.0",
    "next-seo": "^6.6.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.53.0",
    "sharp": "^0.33.5",
    "swr": "^2.2.5",
    "uuid": "^10.0.0"
  },
  "devDependencies": {
    "@next/bundle-analyzer": "^14.2.14",
    "@svgr/webpack": "^8.1.0",
    "@trivago/prettier-plugin-sort-imports": "^4.3.0",
    "@types/node": "^22.7.4",
    "@types/react": "^18.3.11",
    "@types/react-dom": "^18.3.0",
    "@types/uuid": "^10.0.0",
    "autoprefixer": "^10.4.20",
    "cssnano": "^7.0.6",
    "cssnano-preset-advanced": "^7.0.6",
    "eslint": "^8.57.1",
    "eslint-config-next": "^14.2.14",
    "postcss": "^8.4.47",
    "prettier": "^3.3.3",
    "prettier-plugin-tailwindcss": "^0.6.8",
    "tailwindcss": "^3.4.13",
    "typescript": "^5.6.2"
  }
}

sentry.client.config.ts

import * as Sentry from '@sentry/nextjs';

import { API_BASE_URL, APP_BASE_URL, ENVIRONMENT, RELEASE, SENTRY_DSN, SENTRY_TRACES_SAMPLE_RATE } from '@/config';

Sentry.init({
  dsn: SENTRY_DSN,
  release: RELEASE,
  environment: ENVIRONMENT,
  tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
  tracePropagationTargets: [APP_BASE_URL, API_BASE_URL],
  integrations: [Sentry.browserTracingIntegration()],
});

instrumentation.ts

import * as Sentry from '@sentry/nextjs';

import { API_BASE_URL, ENVIRONMENT, RELEASE, SENTRY_DSN, SENTRY_TRACES_SAMPLE_RATE } from '@/config';

export async function register() {
  Sentry.init({
    dsn: SENTRY_DSN,
    release: RELEASE,
    environment: ENVIRONMENT,
    tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
    tracePropagationTargets: [API_BASE_URL],
  });
}

export const onRequestError = Sentry.captureRequestError;

Steps to Reproduce

  1. Enable tracePropagationTargets and configure it to point to your backend server.
  2. Make HTTP requests using fetch inside middleware or during SSG generation in a Next.js project.
  3. When performing an HTTP request, Sentry will add the Baggage and Sentry-Trace headers to the outgoing requests.
  4. These headers will be received by the backend (using sentry-go).
  5. The Sentry-Trace header will contain two trace IDs, for example:
    0b7da23d63cc4a7d9436abf37ace0e0c-9510fafae5f1c2c5-1,faca5d26f53d660657d9e4b073fb8da2-74dbb120f6aca02a-1
  6. Due to the presence of two trace IDs, the backend cannot correctly parse the Parent Span ID, leading to incorrect transaction linking.
    Image

Expected Result

The Sentry-Trace header should contain only a single trace ID.

Actual Result

The Sentry-Trace header contains multiple trace IDs.

@lforst
Copy link
Member

lforst commented Oct 7, 2024

Hi, thanks for moving this issue here! Before I go and try reproduce this. How are you calling your Next.js app?

@shlyamster
Copy link
Author

shlyamster commented Oct 7, 2024

@lforst My application is running in docker node:22-alpine, started using the node server.js command from the standalone folder. Before that, the Next.js files are built using the next build command. Below is my next.config.js file.

const packageInfo = require('./package.json');
const { PHASE_PRODUCTION_SERVER } = require('next/constants');
const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' });
const { withSentryConfig } = require('@sentry/nextjs');

const parseEnv = variable =>
  variable === undefined ||
  variable === null ||
  variable === '' ||
  variable === 'undefined' ||
  variable === 'null' ||
  variable === '<nil>'
    ? undefined
    : variable;

const buildId = parseEnv(process.env.NEXT_PUBLIC_BUILD_ID);
const environment = parseEnv(process.env.NODE_ENV) || 'development';
const release = `${packageInfo.name}@${packageInfo.version}+${buildId || environment}`;

const appBaseUrl = new URL(parseEnv(process.env.NEXT_PUBLIC_APP_BASE_URL));
const apiBaseUrl = new URL(parseEnv(process.env.NEXT_PUBLIC_API_BASE_URL));

module.exports = phase => {
  const isServer = phase === PHASE_PRODUCTION_SERVER;

  /** @type {import('next').NextConfig} */
  const nextConfig = {
    generateBuildId: () => buildId || environment,
    output: buildId ? 'standalone' : undefined,
    compress: !buildId,
    cacheHandler: isServer && buildId ? require.resolve('./cache-handler.mjs') : undefined,
    cacheMaxMemorySize: isServer && buildId ? 0 : undefined,
    logging: {
      fetches: {
        fullUrl: !buildId,
      },
    },
    poweredByHeader: false,
    experimental: {
      instrumentationHook: true,
      serverActions: { allowedOrigins: appBaseUrl ? [appBaseUrl.host] : undefined },
    },
    transpilePackages: ['next-mdx-remote'],
    images: {
      minimumCacheTTL: 604800,
      formats: ['image/avif', 'image/webp'],
      deviceSizes: [375, 640, 768, 828, 1024, 1080, 1280, 1440, 1570, 1920, 2048, 2560],
    },
  };

  /** @type {Parameters<import('@sentry/nextjs').withSentryConfig>[1]} */
  const sentryBuildOptions = {
    org: parseEnv(process.env.NEXT_PUBLIC_SENTRY_ORG),
    project: packageInfo.name,
    authToken: parseEnv(process.env.SENTRY_AUTH_TOKEN),
    telemetry: false,
    silent: !!buildId,
    hideSourceMaps: !!buildId,
    disableLogger: !!buildId,
    tunnelRoute: '/api/monitoring-tunnel',
  };

  return withBundleAnalyzer(withSentryConfig(nextConfig, sentryBuildOptions));
};

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 7, 2024
@lforst
Copy link
Member

lforst commented Oct 7, 2024

Ah sorry, I meant how the middleware is invoked as in how the HTTP request to your Next.js app is made 😄

@shlyamster
Copy link
Author

shlyamster commented Oct 7, 2024

@lforst I have middleware enabled for the following routers.

export const config = {
  matcher: ['/((?!api|_next|.*\\..*).*)'],
};

I have complex business logic to call middleware depending on URL and user authorization. But I always have at least 1 middleware function that is always called. To implement calling different middlewares we use @nimpl/middleware-chain library. My middleware is similar to the example from the library. Unfortunately I can't provide the exact source code of my middleware due to privacy.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 7, 2024
@lforst
Copy link
Member

lforst commented Oct 8, 2024

What I meant is, what causes your server to be hit to generate these traces? 😂 I assume the answer is "People open our website in their browser".

@shlyamster
Copy link
Author

@lforst To reproduce the error it is enough to have any static page created in app directory and at least one middleware via @nimpl/middleware-chain library. After that it is enough to visit this page, when GET request to this page will be called and processed by middleware, which I understand adds an additional Trace ID. Unfortunately I can hardly explain the problem more precisely because I am more a backend developer than a frontend one. If you can tell me how I can do profiling or logging, I will be happy to attach the results from my application.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 8, 2024
@shlyamster
Copy link
Author

@lforst Additionally, I can add that inside the middleware the fetch call is executed, which receives the Sentry-Trace header with two Trace IDs.

@lforst
Copy link
Member

lforst commented Oct 8, 2024

@shlyamster Thanks! I have a hunch, but I don't know for sure whether I am right. Maybe this fixes it: #13907

(Side note: None of this is happening in the frontend so you should be in your happy place as a backend dev 😄)

Copy link
Contributor

A PR closing this issue has just been released 🚀

This issue was referenced by PR #13907, which was included in the 8.35.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Package: nextjs Issues related to the Sentry Nextjs SDK
Projects
Archived in project
2 participants