Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

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

Aberta Para iniciantes
#24,672 1 comentário 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
2/5
Tempo estimado
1-3 horas
Facilidade para iniciantes
75/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
javascript, next.js, typescript

Direção de pesquisa

O problema está nos arquivos de instrumentação de roteamento do cliente do Next.js: build/cjs/client/routing/appRouterRoutingInstrumentation.js e provavelmente um arquivo similar para o caminho do patch do roteador. Procure pela atribuição de normalizedHref. A correção é proteger a concatenação para que ela se aplique apenas a caminhos relativos à raiz (aqueles que começam com '/'), espelhando a lógica do addPathPrefix do Next.js. Teste configurando um aplicativo Next.js App Router com um basePath, usando o Sentry e verificando os nomes das transações de navegação após um router.push com uma URL absoluta.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

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.

Linguagem predominante
TypeScript
Estrelas
8.7k
Forks
1.9k
Merge médio
1d 16h
PRs com merge (30d)
576

Guia de contribuição

Abrir o guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de getsentry/sentry-javascript

Todas as issues de getsentry/sentry-javascript

Issues semelhantes

Mais issues de TypeScript

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.