Next.js: basePath is concatenated onto absolute router.push hrefs, corrupting navigation transaction names
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 75/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- javascript, next.js, typescript
- Domaine
- backend-api-design, observability-sre
Piste de recherche
Le problème se trouve dans les fichiers d'instrumentation de routage client de Next.js : build/cjs/client/routing/appRouterRoutingInstrumentation.js et probablement un fichier similaire pour le chemin du correctif du routeur. Cherchez l'affectation de normalizedHref. La correction consiste à protéger la concaténation pour qu'elle ne s'applique qu'aux chemins relatifs à la racine (ceux commençant par '/'), en reflétant la logique de addPathPrefix de Next.js. Testez en configurant une application Next.js App Router avec un basePath, en utilisant Sentry et en vérifiant les noms des transactions de navigation après un router.push avec une URL absolue.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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/nextjs10.22.0; also present in11.0.0(latest at time of writing)next15.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
- Next.js App Router app with
basePath: '/h'and@sentry/nextjsclient instrumentation. - Call
router.push('https://<same-origin>/login')— or, more realistically, have a server component throwredirect('https://<same-origin>/login'). Next'sRedirectBoundarycatches it and callsrouter.push(url)internally, so this needs no unusual application code. - Observe the resulting
navigationtransaction 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.
- Langage dominant
- TypeScript
- Étoiles
- 8.7k
- Forks
- 1.9k
- Merge moyen
- 1 j 16 h
- PR mergées (30 j)
- 576
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de getsentry/sentry-javascript
-
Flaky Test React Router Framework Spans Tests
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
getsentry/sentry-javascript#24348 · 1 commentaire ·
-
javascript
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
getsentry/sentry-javascript#24200 · 2 commentaires ·
-
javascript Task
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
getsentry/sentry-javascript#24134 · 1 commentaire ·
-
Cloudflare Workers javascript Tests
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
getsentry/sentry-javascript#24051 · 1 commentaire ·
-
Bug Bun javascript
Difficulté 2/5 1-3 heures Accessibilité débutants 92/100
getsentry/sentry-javascript#24045 · 1 commentaire ·
Toutes les issues de getsentry/sentry-javascript
Issues similaires
-
VerificationGate: ATTRIBUTION quote guard never matches a normal quotation (\b around the quote) Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
danielmiessler/LifeOS#2234 ·
-
T: Bug
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
-
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
-
Difficulté 1/5 Moins d'une heure Accessibilité débutants 85/100
-
Mend: dependency security vulnerability untriaged
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100