问题排查
定位常见的安装、集成、内容与部署故障。
先用最小命令复现问题,阅读第一条有意义的错误,并在配置源头修复。排查时不要提交
.env、生成的 .source 或本地构建产物。
安装与构建
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
pnpm install 大量改依赖或拒绝 lockfile | 包管理器/版本错误,或 lockfile 被修改 | package.json、pnpm-lock.yaml | 使用 pnpm 和 pnpm install;不要一上来就删除 lockfile |
pnpm lint 报格式问题 | Biome 诊断 | 报错文件、biome.json | 运行 pnpm format,检查 diff,再运行 pnpm lint |
pnpm build 找不到 alias/module | 依赖缺失、大小写错误或生成内容过期 | 导入路径、tsconfig.json、package.json | 修正导入/依赖;若来自 .source,重新生成 Fumadocs 内容 |
| 开发正常但生产构建失败 | 服务端渲染读到无效 env/数据,或 Client/Server 边界错误 | 构建输出中第一个失败路由 | 本地运行 pnpm build 并修复该路由,不要压制错误 |
PostgreSQL 与 Drizzle
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
| 连接被拒绝/超时 | PostgreSQL 未启动、主机/端口错误或托管数据库阻止网络 | DATABASE_URL、提供商网络策略 | 用 PostgreSQL 客户端测试同一 URL;先修连通性再改 schema |
| 认证失败或数据库不存在 | 用户/密码/库名错误,常见于特殊字符转义 | DATABASE_URL | 从提供商重新复制 URL;手写时对凭据做 URL 编码 |
relation ... does not exist | schema 未应用到当前数据库 | drizzle.config.ts、src/lib/db/schema/ | 确认目标库,再为本地/模板设置运行 pnpm exec drizzle-kit push |
| 修改 auth schema 后认证故障 | Better Auth adapter 预期与 Drizzle 表不一致 | src/lib/auth.ts、src/lib/db/schema/auth.ts | 有计划地同步 schema,并应用到正确数据库 |
| 生产连接过多 | 每实例连接池总量超过提供商限制 | src/lib/db/index.ts、托管池配置 | 使用池化 PostgreSQL 端点,并按总实例并发调整连接数 |
模板没有已提交的迁移历史,不要假设 drizzle-kit migrate 已可直接使用。参见
数据库。
Better Auth、Cookie 与重定向
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
登录成功仍跳到 /auth/login | Cookie 缺失、属于其他 origin,或 HTTP/HTTPS/域名不一致 | 浏览器 Cookie、BETTER_AUTH_URL、请求主机 | 统一规范 origin,设置正确 URL,并清除旧 Cookie |
| Auth 端点返回服务端错误 | secret 缺失/过弱,或数据库/邮件故障 | BETTER_AUTH_SECRET、服务端日志、数据库/Resend 配置 | 生成强 secret,修复下游服务并重启 |
| 以为 proxy 会保护 API,但 API 仍可访问 | src/proxy.ts 仅按 Cookie 重定向页面,且跳过 /api | Route Handler 认证代码 | 在每个受保护服务端边界调用 auth.api.getSession({ headers: await headers() }) |
| 本地正常,反向代理后失败 | 对外 origin/协议与认证 URL 不同 | 转发 host/proto、BETTER_AUTH_URL | 配置规范 HTTPS URL 和平台可信代理头 |
参见身份认证。
OAuth 回调
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
| 提供商提示 callback/redirect 不匹配 | 注册 URL 的主机、协议、端口、locale 或 provider 不同 | OAuth 控制台、BETTER_AUTH_URL | 精确注册 {BETTER_AUTH_URL}/api/auth/callback/{provider} |
| OAuth 按钮立即失败 | Client ID/secret 缺失或来自另一应用/环境 | GITHUB_*、GOOGLE_*、提供商控制台 | 使用匹配的凭据对,修改 env 后重启 |
| 账户关联结果意外 | 多个提供商邮箱相同且启用了 linking | src/lib/auth.ts | 修改前审查模板关联策略,并用已有账户测试 |
Resend 邮件
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
| 验证/重置/联系表单发送报错 | RESEND_API_KEY 缺失、无效或被提供商拒绝 | 服务端日志、.env、src/lib/email/ | 使用有效的服务端 key,并用允许的收发件地址重试 |
| 测试发件人可用,自有域名不可用 | 域名/DNS 未验证,或 fromEmail 域名错误 | Resend 域名状态、website-config.ts | 验证 DNS,再使用该域名下的发件地址 |
| 已接受但未送达 | 垃圾邮件、退信、抑制列表或收件人问题 | Resend 投递事件 | 检查提供商事件;永久退信不要无限重试 |
参见邮件。
Creem 结账与 Webhook
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
| 创建结账失败 | sandbox/live key、server index 与产品 ID 不属于同一环境 | CREEM_SERVER_IDX、CREEM_API_KEY、NEXT_PUBLIC_CREEM_PRODUCT_* | 使用同一环境的 key/产品 ID;改公开 ID 后重新构建 |
Webhook 返回 401 Invalid signature | secret 错误、缺少 creem-signature 或 body 被代理改写 | CREEM_WEBHOOK_SECRET、端点/日志 | 复制同一 Creem 端点的 secret,让提供商原始请求直接到达路由 |
Webhook 返回配置 500 | 运行时没有 secret | 运行时 env | 在实际部署设置 CREEM_WEBHOOK_SECRET 并重启/重部署 |
| 支付成功但 UI 不变 | 事件未处理、Webhook 未送达或仪表盘仍为 mock | Creem 投递日志、/api/payment/notify/creem、数据库行 | 重放已验证 sandbox 事件,检查订单/订阅行,并让 UI 读取真实数据 |
Webhook 必须使用精确路径 /api/payment/notify/creem。参见
支付。
OpenAI 聊天
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
| API key 缺失/无效 | 未设置或设置了错误的 OPENAI_API_KEY | 服务端 env 与路由日志 | 设置有效的服务端 key 并重启 |
| 找不到/不支持模型 | 客户端选择器或请求模型无法由当前提供商调用 | ChatBot.tsx、/api/chat 请求 | 选择支持的模型,并在服务端执行相同白名单 |
| Search 开关没有网页结果 | 当前代码只发送 tools: {} | src/app/api/chat/route.ts | 配置真实服务端搜索工具,或移除/禁用开关 |
| 流中断但 UI 反馈很少 | 提供商/连接错误没有映射为产品错误状态 | 网络响应和服务端日志 | 添加结构化流错误、超时与用户安全提示 |
参见 AI 聊天。
Replicate 媒体
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
| 提供商“未配置” | 惰性工厂创建时没有 REPLICATE_API_TOKEN | 运行时 env、src/lib/ai/*/index.ts | 设置令牌并重启进程 |
创建 prediction 返回 500 | 模型 ID 或模型专属输入映射错误 | 路由日志、provider 实现、Replicate 错误 | 对照模型 schema 检查 createTask();不要盲传 UI 选项 |
| 轮询一直不结束 | 远程任务慢/卡住、未知状态,或客户端无总超时 | /query 响应、Replicate 任务 | 在 Replicate 检查任务;增加有上限的退避、超时、取消与持久化 |
| 成功但看不到媒体 | 输出结构未识别,或提供商 URL 过期/CORS 阻止下载 | taskInfo.output、URL 提取器 | 扩展对应提取器;把最终资源复制到自有对象存储 |
参见 AI 媒体生成。
Fumadocs 与 MDX
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
集合导入或 .source 类型缺失 | 生成目录缺失/过期 | .source/、source.config.ts、tsconfig.json | 停止 dev,删除 .source/,运行 pnpm dev 或 pnpm build |
| 构建提示 frontmatter 无效 | schema 必填字段类型/格式错误 | 失败 MDX、source.config.ts | 修正 frontmatter;日期用 YYYY-MM-DD,标签用数组 |
| 文档 404 或未出现在导航 | 文件/翻译缺失,或 meta.json slug 错误 | content/docs/、最近的 meta.json | 创建页面对,并让文件名与导航 slug 完全一致 |
| MDX 组件未定义 | 该渲染器收到的映射中没有组件 | mdx-components.tsx、docs/blog/legal 页面 | 注册共享组件映射,并传给相应渲染器 |
不要手改 .source。参见内容。
国际化路由
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
/en/... 被重定向或链接不一致 | 默认英文使用 localePrefix: "as-needed" | src/i18n/routing.ts、导航 helpers | 使用 @/i18n/navigation;英文无 /en,中文有 /zh |
| 新 locale 404 | 只在一个位置加入 locale,或消息/内容缺失 | routing、request 配置、messages、proxy regex | 更新所有 locale 列表,提供消息/内容后再链接 |
| API 请求意外带 locale | API 被 locale middleware 处理 | src/proxy.ts matcher/API 提前返回 | 保持 /api 不经过 locale 处理 |
参见国际化。
Docker
| 症状 | 常见原因 | 检查位置 | 安全修复 |
|---|---|---|---|
容器因缺少 server.js 退出 | 未启用 standalone 输出,或复制了错误阶段/产物 | next.config.mjs、Docker 构建日志 | 保留 output: "standalone",重新构建提供的多阶段 Dockerfile |
| 容器运行但连不上 PostgreSQL | localhost 指向容器自身 | 运行时 DATABASE_URL、Docker 网络 | 使用数据库服务名/host gateway,并从同一网络测试 |
| 修改运行时 env 后公开配置仍旧 | NEXT_PUBLIC_* 已在 pnpm build 内联 | builder 阶段 env、部署产物 | 构建时提供公开值,并重新构建镜像 |
| 上传文件消失 | public/uploads 位于临时/被替换容器 | 上传路由、volume | 改用持久对象存储;仅挂 volume 仍需处理多实例 |
Next.js 16 检查项
- 异步请求 API: 把
params、searchParams声明为 Promise 并await;headers()、cookies()也要await。 - 使用
proxy.ts,不是middleware.ts: 模板采用 Next.js 16 proxy 约定, 不要照旧教程再添加一份 legacy middleware。 - Server/Client 边界: Client Component 不能是
async;浏览器 Hook 需要"use client";服务端传到客户端的 props 必须可序列化;secret/数据库代码留在服务端。 - 构建期公开变量: 构建后修改
NEXT_PUBLIC_*不会更新浏览器 bundle,必须 重新构建并部署。
若问题仍存在,请记录失败命令、第一条相关堆栈、路由、HTTP 状态/响应,以及脱敏后的 环境变量名称(不要记录 secret 值)。这些信息通常足以让下一轮排查快速收敛。
