Next.js: basePath is concatenated onto absolute router.push hrefs, corrupting navigation transaction names
还没有人认领这个 Issue。
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 75/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- javascript, next.js, typescript
调研方向
问题出在 Next.js 客户端路由插桩文件中:build/cjs/client/routing/appRouterRoutingInstrumentation.js 以及可能存在的 router-patch 路径下的类似文件。查找 normalizedHref 的赋值。修复方法是保护拼接操作,使其仅适用于根相对路径(以 '/' 开头的路径),以匹配 Next.js 的 addPathPrefix 逻辑。测试方法:设置一个带有 basePath 的 Next.js App Router 应用,使用 Sentry,并验证在使用绝对 URL 进行 router.push 后的导航事务名称。
由索引模型根据 Issue 内容生成。
描述
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.
- 主要语言
- TypeScript
- 星标
- 8.7k
- 派生
- 1.9k
- 平均合并
- 1 天 16 小时
- 30 天内合并 PR
- 576
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
getsentry/sentry-javascript 的其他 Issue
-
Flaky Test React Router Framework Spans Tests
难度 2/5 1-3 小时 新手友好度 68/100
getsentry/sentry-javascript#24348 · 1 条评论 ·
-
javascript
难度 2/5 1-3 小时 新手友好度 75/100
getsentry/sentry-javascript#24200 · 2 条评论 ·
-
javascript Task
难度 2/5 1-3 小时 新手友好度 82/100
getsentry/sentry-javascript#24134 · 1 条评论 ·
-
Cloudflare Workers javascript Tests
难度 2/5 1-3 小时 新手友好度 78/100
getsentry/sentry-javascript#24051 · 1 条评论 ·
-
Bug Bun javascript
难度 2/5 1-3 小时 新手友好度 92/100
getsentry/sentry-javascript#24045 · 1 条评论 ·
查看 getsentry/sentry-javascript 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 75/100
vercel-labs/just-bash#464 ·
-
looksLikeSlug() is ASCII-only, so non-Latin entity slugs (e.g. Korean) skip exact match and collapse 未关闭
难度 2/5 1-3 小时 新手友好度 75/100
-
难度 2/5 1-3 小时 新手友好度 65/100
-
难度 2/5 1-3 小时 新手友好度 65/100
-
难度 1/5 1 小时以内 新手友好度 90/100
TanStack/tanstack.com#1293 ·