Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Next.js: basePath is concatenated onto absolute router.push hrefs, corrupting navigation transaction names

オープン 初心者向け
#24,672 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
75/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
javascript, next.js, typescript

調査の方向性

問題はNext.jsのクライアントルーティング計装ファイルにあります: build/cjs/client/routing/appRouterRoutingInstrumentation.js およびおそらくルーターパッチパス用の類似ファイルです。normalizedHref の代入を探してください。修正は、連結をガードしてルート相対パス('/'で始まるもの)にのみ適用されるようにし、Next.jsの addPathPrefix ロジックを反映させることです。basePathを設定したNext.js App Routerアプリをセットアップし、Sentryを使用して、絶対URLでの router.push 後のナビゲーショントランザクション名を検証することでテストしてください。

索引モデルが issue の本文から書いたものです。

説明

Browser Bug Next.js Traces Waiting for: Product Owner

Summary

@sentry/nextjs prepends basePath to the router.push / router.replace argument with an unguarded string concatenation. When the argument is an absolute URL, the two are glued together and the navigation span is named something like:

/hhttps://example.com/login

instead of /login. The navigation itself works correctly — only the span name is corrupted — so this shows up as junk entries in the transaction list and in dashboards, not as a user-facing failure.

Versions

  • @sentry/nextjs 10.22.0; also present in 11.0.0 (latest at time of writing)
  • next 15.5.18, App Router, basePath: '/h'
  • Affects both navigation instrumentation modes (see below)

Root cause

build/cjs/client/routing/appRouterRoutingInstrumentation.js, in the transition-start-hook path:

const basePath = process.env._sentryBasePath ?? globalWithInjectedBasePath._sentryBasePath;
const normalizedHref = basePath && !href.startsWith(basePath) ? `${basePath}${href}` : href;
const unparameterizedPathname = new URL(normalizedHref, WINDOW.location.href).pathname;

With basePath = '/h' and href = 'https://example.com/login', href.startsWith('/h') is false, so the result is '/h' + 'https://example.com/login', and new URL(...).pathname faithfully returns /hhttps://example.com/login.

The same expression appears in the router-patch path, so both modes are affected.

Note the second-order effect: an href that already carries the base path — https://example.com/h/payments — is still concatenated, because as a string it starts with https, not /h.

Why Next.js itself is unaffected

Next's own addPathPrefix guards on the leading slash:

function addPathPrefix(path, prefix) {
  if (!path.startsWith('/') || !prefix) {
    return path;
  }
  ...
}

So Next leaves absolute URLs alone, treats a same-origin absolute URL as an internal navigation, and routes correctly. Only the Sentry span name diverges from reality.

Reproduction

  1. Next.js App Router app with basePath: '/h' and @sentry/nextjs client instrumentation.
  2. Call router.push('https://<same-origin>/login') — or, more realistically, have a server component throw redirect('https://<same-origin>/login'). Next's RedirectBoundary catches it and calls router.push(url) internally, so this needs no unusual application code.
  3. Observe the resulting navigation transaction name.

Expected: /login
Actual: /hhttps://<same-origin>/login

Absolute redirect targets are not exotic in a basePath app: Next's server redirect() runs the location through addPathPrefix, so an absolute URL is the documented way to send a user to a path outside the base path. Those same absolute URLs then reach the client router whenever the redirect is hit during a soft navigation.

We see seven distinct corrupted names in production across two apps over 90 days.

Suggested fix

Mirror Next's guard — only prefix root-relative paths:

-const normalizedHref = basePath && !href.startsWith(basePath) ? `${basePath}${href}` : href;
+const normalizedHref =
+  basePath && href.startsWith('/') && !href.startsWith(basePath) ? `${basePath}${href}` : href;

Both occurrences need it. The router-patch branch additionally guards typeof href === 'string' already, which the hook branch does not.


Investigated and written with Claude Code.

主要言語
TypeScript
スター
8.7k
フォーク
1.9k
平均マージ
1日 16時間
マージ済み PR(30日)
576

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

getsentry/sentry-javascript のほかの issue

getsentry/sentry-javascript の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。