部署成功、build log 全绿,但打开线上页面或调 API 返回 500: INTERNAL_SERVER_ERROR,下方通常还带一行错误码,比如 FUNCTION_INVOCATION_FAILED 或 EDGE_FUNCTION_INVOCATION_FAILED。这种”build 过了运行炸”几乎都不是代码语法问题,而是运行时上下文缺失:env var 没同步到 Production scope、Edge function 用了 Node-only API、数据库连接池被打满,或者上游 API 调用一直不返回。
最快的修复方式: 跑 vercel logs --environment production --status-code 5xx --expand --since 1h,看堆栈前两行,那就是真正的原因。下面的内容按命中率排序,也就是你在日志里最常看到的顺序。
先判断你属于哪一类
把错误页(或 vercel logs)里显示的错误码对上下面这张表:
| 500 页面上的错误码 | 最可能的原因 | 跳转 |
|---|---|---|
FUNCTION_INVOCATION_FAILED | 未捕获的异常:env var 缺失、import 出错、catch 没 return | 原因 1、2、6 |
FUNCTION_INVOCATION_TIMEOUT | 上游调用或查询在 maxDuration 前一直没返回 | 原因 3 |
EDGE_FUNCTION_INVOCATION_FAILED | Edge function 用了 Node-only API(fs、crypto、Buffer、process) | 原因 2 |
NO_RESPONSE_FROM_FUNCTION | handler 走完了但没返回 Response | 原因 6 |
| 500 且日志里有 DB 报错 | 连接池耗尽 | 原因 5 |
完整的平台错误码列表见 Vercel 错误码参考。
常见原因
按命中率从高到低排列。
1. Production 环境变量缺失或没勾选 scope
Preview 上跑得好好的,到 Production 就 500。打开 Vercel dashboard,进 Settings, Environment Variables,看每条 var 后面的环境标签:Production、Preview、Development 三个独立勾选。常见疏漏是新加的 OPENAI_API_KEY 只在 Preview 启用,没在 Production 启用。
TypeError: Cannot read properties of undefined (reading 'startsWith')
at new OpenAI (/var/task/node_modules/openai/index.js:42)
如何判断: vercel env ls production 列出 production 实际能拿到的 env vars,对照代码里所有 process.env.XXX 的引用。某个引用解析成 undefined,那就是问题所在。
2. Edge runtime 用了 Node-only API
函数顶部写了 export const runtime = 'edge',但代码里 import fs from 'fs'、require('crypto').createHash、读 process.cwd()、或用了 Node 版的 Buffer。本地 dev 走的是 Node 所以没事,部署到 Edge 就炸,因为 Edge 只提供 Web API 的一个子集。
Error: The package "fs" wasn't found on the file system but is built into node.
在 Next.js 构建里你常会看到另一种写法:
A Node.js API is used (process.cwd at line: 1451) which is not supported in the Edge Runtime.
如何判断: 在 function logs(或 build 输出)里搜 not supported in the Edge Runtime 或 built into node。500 页面一般会显示 EDGE_FUNCTION_INVOCATION_FAILED。
3. 上游 API 调用没设超时
调 OpenAI、Anthropic、Stripe 这类外部 API 时没加 AbortController,对方一直挂着,函数等到时间耗尽被掐,回复还没到。
Task timed out after 300.00 seconds
FUNCTION_INVOCATION_TIMEOUT
注意这个时长:截至 2026 年 6 月,Vercel 默认开启 Fluid Compute,所以除非你手动调低,Hobby、Pro、Enterprise 的默认 maxDuration 都是 300 秒(5 分钟)。(旧版 Vercel 文档和教程里写的 Hobby 10 秒 / Pro 60 秒,那是 Fluid Compute 之前的数据。)一个函数”挂”满整整 300 秒,基本都是上游缺超时,而不是代码本身慢。
如何判断: function logs 里出现 Task timed out,且时长正好等于你配置的 maxDuration。
4. 冷启动过慢 + 大依赖
函数 bundle 太大会拖慢冷启动,首字节时间可能撑过 maxDuration。常见原因:只用一个子模块却把整个 aws-sdk 或 firebase-admin 引进来。未压缩 bundle 上限是 250 MB,实际要远低于这个值才安全。
如何判断:
vercel inspect <deployment-url> --logs
# 在 Functions 区段看 bundle 体积和冷启动耗时
5. 数据库连接池耗尽
Serverless 每次调用都可能新建一个连接。PostgreSQL/MySQL 默认并发上限大约 100 个,一波突发流量就把池打满,后续函数全部 500。
Error: remaining connection slots are reserved for non-replication superuser connections
如何判断: DB provider 仪表盘(Supabase、Neon、PlanetScale)里看 active connections 是不是一直贴着上限。
6. catch 块记了日志但没返回 response
try { ... } catch (e) { console.error(e) } 没 return new Response(...),函数走完没回应,Vercel 报 NO_RESPONSE_FROM_FUNCTION 或 500。
如何判断: function logs 里有错误堆栈,但 5xx 之前没有业务日志,说明响应没走完。
最短修复路径
Step 1:用 vercel logs 抓真实错误
vercel logs 命令在 2026 年 2 月重写过,现在支持带原生过滤参数查询历史日志,不用再把所有东西 pipe 给 grep。直接过滤到 production 的 500:
# 最近 1 小时所有 production 5xx 错误,带完整堆栈
vercel logs --environment production --status-code 5xx --expand --since 1h
# 缩到只看 edge function,或只看某一次请求
vercel logs --source edge-function --level error --since 1h
vercel logs --request-id <req_xxxxx> --expand
# 一边复现一边实时跟踪(最多跟 5 分钟)
vercel logs --follow
想要机器可读的输出?加 --json 再 pipe 给 jq。你也可以走 dashboard 路径 Deployments, 选最新, Functions, Logs,但 CLI 更快、可全文搜索。复制完整堆栈,前两行就是真因。
Step 2:核对 env vars
# 列出 production scope 的所有 env var(只显示 key)
vercel env ls production
# 拉到本地比对代码引用
vercel env pull .env.production
diff <(grep -oE '^[A-Z_]+=' .env.production | sort) \
<(grep -roE 'process\.env\.[A-Z_]+' src/ | sort -u)
新加或改了 scope 的 env var 必须 redeploy 才生效(dashboard 点 Redeploy,或推一个新 commit)。只改变量不会回头打到正在运行的那次部署上。
Step 3:Edge function 改回 Node 验证
如果堆栈里出现 Edge Runtime 或 not supported,把 runtime 改回 Node:
// app/api/chat/route.ts
export const runtime = 'nodejs'; // 改自 'edge'
export const maxDuration = 30; // 显式上限;开了 Fluid Compute 默认是 300
Redeploy 后观察几个小时。若稳定,再决定是要重构成 Edge-safe 版本(用 fetch 替代 axios、用 Web Crypto 的 crypto.subtle 替代 Node crypto),还是干脆留在 Node。Edge 换来的只是更低延迟;对大多数要调上游模型的 API route 来说,Node 是更稳妥的默认选择。
Step 4:所有上游 fetch 加超时
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 8000);
try {
const res = await fetch('https://api.openai.com/v1/...', {
signal: controller.signal,
});
return Response.json(await res.json());
} catch (e) {
if (e.name === 'AbortError') {
return new Response('Upstream timeout', { status: 504 });
}
console.error(e);
return new Response('Internal error', { status: 500 });
} finally {
clearTimeout(timeout);
}
关键:每个 catch 都必须 return 一个 Response,别只 console.error。一个 8 秒的 abort 会给客户端干净地返回 504,而不是让函数烧满整整 300 秒再以超时收场。
Step 5:数据库用连接池
Serverless 不要直连 Postgres。用 Prisma Accelerate、Neon 的 @neondatabase/serverless,或 Supabase 的 transaction pooler URL:
// 使用 pgBouncer pooler,端口 6543 而非 5432
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL_POOLER,
max: 1, // serverless 每实例只用 1 个连接
});
如何确认已修复
- Redeploy 后跑
curl -i https://your-app.vercel.app/api/<route>,确认返回HTTP/2 200。 - 重新跑
vercel logs --environment production --status-code 5xx --since 10m。结果为空才是你想要的。 - 如果原因是超时或 DB 连接池,制造一小波突发(比如
for i in {1..30}; do curl -s -o /dev/null -w "%{http_code}\n" https://your-app.vercel.app/api/<route> & done),确认每个响应都是200。
预防建议
- CI 里加 env var 检查:grep 出代码里所有
process.env.XXX,对照vercel env ls production,缺一个就 fail。 - 所有上游调用强制加超时(8 秒以内);catch 块强制
return一个 Response。 - 给 Edge function 加 lint,禁止 Node-only import(
fs、path、crypto、net、process)。 - 部署后跑一次 health-check,curl 关键 API 端点并断言 200。
- 数据库一律走 pooler URL;active connections 到 80% 上限时告警。
- 给每个函数设显式
maxDuration,让卡住的请求快速失败,而不是耗满 300 秒的默认值。
常见问题
为什么 Preview 正常,只有 Production 才 500?
基本都是某个 env var 只勾了 Preview 没勾 Production。跑 vercel env ls production 和 vercel env ls preview 对比,一个有一个没有的那条就是嫌疑。
日志说”超时 300 秒”但我的代码很快,为什么?
你撞到的是默认 maxDuration,因为 Fluid Compute 是开着的。300 秒是上限,不是代码真实运行时间;一个快函数只有在卡着等一个永不返回的上游调用或查询时才会烧满 300 秒。按 Step 4 加上 AbortController,让调用几秒内就失败。
实际的堆栈在哪看,而不是只有 500: INTERNAL_SERVER_ERROR?
浏览器只显示通用错误码。真正的异常在 runtime logs 里:vercel logs --environment production --status-code 5xx --expand,或 dashboard 的 Logs 页。--expand 会在每条请求行下面打出完整消息。
改了 env var 一定要 redeploy 吗? 要。env var 是在 build/deploy 时注入的,已存在的部署会一直用旧值,直到你 redeploy 或推新 commit。
EDGE_FUNCTION_INVOCATION_FAILED 和 FUNCTION_INVOCATION_FAILED 有什么区别?
带 EDGE_ 的表示故障发生在 Edge function,最常见的是它用了 Node-only API。不带的那个表示普通(Node)serverless 函数抛了异常。修复路径不同:Edge 故障通常是把 runtime 改成 'nodejs' 或去掉那个 Node API(原因 2)。