---
date: 2026-05-17
status: 工程化保险已加（清缓存命令成为删 route 标准动作）
tags: [nextjs, turbopack, build, route-deletion, type-validator]
related-errs: []
related-learnings: [2026-05-17-nextjs-turbopack-stale-dev-cache.md]
---

# ERR-20260517-002 — Next.js 16 删 route 后 `next build` 因 `.next/dev/types/validator.ts` stale 失败

## 现象

在 slot 里删了 `frontend/src/app/(modules)/flow-diagram/` 路由目录及其子页面（list / new / [id] / view/[id]）之后，`cd frontend && npm run build` 报：

```
Failed to compile.

.next/dev/types/validator.ts:627:39
Type error: Cannot find module '../../../src/app/(modules)/flow-diagram/[id]/page.js' or its corresponding type declarations.

> 627 |   const handler = {} as typeof import("../../../src/app/(modules)/flow-diagram/[id]/page.js")
      |                                       ^
Next.js build worker exited with code: 1 and signal: null
```

`Compiled successfully in 61s` 已经过了，错误发生在后续 `Running TypeScript ...` 阶段。

## 直接原因

Next.js 16 (Turbopack) 在 `next dev` 期间会把每个 app router 路由的类型 stub 写到
**`.next/dev/types/validator.ts`**，里面长这样：

```ts
type __IsExpected<Specific extends AppPageConfig<"/flow-diagram/[id]">> = Specific
const handler = {} as typeof import("../../../src/app/(modules)/flow-diagram/[id]/page.js")
```

删 route 目录后 **不会自动清理这个文件**，下次跑 `next build` 时 TypeScript 阶段读到这个 stub，发现引用的 `page.js` 不存在 → 编译失败。

## 元根因

Turbopack 的类型缓存生命周期跟源码不绑：

1. 文件夹名 `.next/dev/types/` 是误导性的——名字带 `dev` 但 `next build` 的 TypeScript pass 也读它
2. Next.js 没有 "源码删了就清对应 type stub" 的钩子
3. Turbopack incremental 模式优先复用缓存，不做完整性校验

跟既有 learning `2026-05-17-nextjs-turbopack-stale-dev-cache.md` **场景不同**：
- 那个：dev 运行时 chunk 找不到 → 整站 500（运行时）
- 这个：build TypeScript pass 找不到 page.js stub → 退出码 1（构建时）

## 解法

**删除 Next.js app router 路由后，跑 build / 提交前必须清 `.next/`**：

```bash
cd frontend && rm -rf .next && npm run build
```

清完重新构建一次性通过。`.next/` 是构建产物，删它没副作用，dev server 也会自动重建。

## 监控点

- error 含 `.next/dev/types/validator.ts` + `Cannot find module ... /page.js`
- 触发条件：删 / 重命名 `frontend/src/app/**/(modules|*)/.../page.tsx` 后第一次 `next build`
- 不会在 dev server 上立刻暴露（dev 时该路由已经不被访问就不会重新生成 validator stub，但缓存里旧的 stub 留着）

## 工程化保险

**Option A（已采用）**：把 `rm -rf .next` 列为"删路由"的标准前置动作，在 CLAUDE.md / pre-merge-build-fix skill 里写明。

**Option B（可选）**：在 frontend `package.json` 加 `prebuild` 钩子 `rimraf .next/dev/types/validator.ts`，但会拖慢正常增量构建；目前没必要。

**Option C（pre-commit hook）**：检测 staged diff 中是否有 `D frontend/src/app/.../page.tsx`，若有则强制 `rm -rf .next && npm run build` 校验。**未实施**（频次低，手动注意即可）。

## 复现

```bash
# 任意 slot
cd frontend
rm -rf src/app/\(modules\)/some-existing-route   # 删个现有 route
npm run build                                     # 报 .next/dev/types/validator.ts:xxx Cannot find module
rm -rf .next && npm run build                     # 通过
```
