返回博客

Next.js 16 Turbopack 热添加动态路由后 overlay 卡死——幽灵报错不是代码 bug

下午三点刚过,我给一个 output: "export" 静态导出项目新增了一条动态路由 [id]/page.tsxgenerateStaticParams 枚举了一个静态数组,写法和项目里其他同类路由一模一样。保存,Turbopack 飞速编译,然后——浏览器弹出红色 overlay:

Page "/checkout/[id]/page" is missing param "/checkout/[id]"
in "generateStaticParams()", which is required with "output: export" config.

接下来半小时,我反复确认代码、重新保存、改写法,overlay 纹丝不动。

现象

  • 错误信息里 missing param 的值是字面量路由模板 /checkout/[id],而不是某个具体 id(比如 /checkout/co5)。
  • 同类兄弟路由(同样是 [id]/page.tsx + generateStaticParams)完全正常。
  • 触发时机:dev server 启动之后才新建这个文件(热添加),不是项目初始就有的。
  • 重新保存、多次触发 HMR recompile,overlay 依旧在。

根因

Turbopack 在热添加新路由文件时,有一个窗口期:文件已被 watch 到、页面已渲染,但 generateStaticParams 还未注册进路由参数清单(param manifest)。Next.js dev runtime 在那一刻检测到"有动态路由但没有 params",触发了 overlay。

问题在于:HMR 不会自动关闭这个 overlay。即使后续编译完成、param manifest 已经填入正确数据,之前那条错误信息已经粘在当前 tab 的状态里,持续显示、持续上报。

[id] 字面量出现在错误里,是关键信号——清单里该路由当时注册了零个 param,Next 于是把路由模板本身当作 placeholder 打印出来。如果是真正的"未枚举 id"问题,报错会是具体值(如 co5-258000)。

坑:overlay 存活不代表代码有错

看到 missing param overlay 的第一反应往往是去改 generateStaticParams。但在 Next.js 16 dev 模式下,output: export 不强制校验 generateStaticParams——dev 会渲染任意 param,不报错。真正的 param 校验只在 next build 时执行。

因此:dev overlay 里的 missing param,如果在全新浏览器里完全复现不了,几乎可以断定是陈旧状态,不是代码 bug。

正解

不要先动代码。先验证是不是陈旧 overlay。

  1. 用全新浏览器(或无痕窗口)访问同一路由——硬加载 /checkout/co1、软导航(router.push)、在详情页强制刷新,全部 clean,无 console 错误。代码就没问题。

  2. 清除陈旧 overlay(按成本从低到高):

    • Cmd+Shift+R 强刷受影响的 tab,overlay 消失。
    • 若强刷无效,重启 dev server(pnpm dev),让所有 HMR 客户端重连。
    • 最后手段:rm -rf .next 后再重启。
正解:先开新标签验代码,再强刷旧标签清 overlay

验证顺序:全新 tab/浏览器 → 确认页面正常 → 回到报错 tab 强刷。不要在报错 tab 里反复调试——那是在被幽灵状态带跑。

一句话外卖

dev overlay 里 missing param 值是路由模板字面量(如 [id]),是 Turbopack 热添加路由的陈旧状态信号,开新 tab 验代码、强刷旧 tab 清状态,30 秒解决,不要对着正确代码改半小时。