# The complete Vercel troubleshooting compendium: crushing build failures, function errors, 504/413, 404, and cold starts by cause

> A practical guide to resolving common Vercel production errors by cause. It explains, with real code and faithful to the official docs: FUNCTION_INVOCATION_TIMEOUT(504), FUNCTION_PAYLOAD_TOO_LARGE(413), FALLBACK_BODY_TOO_LARGE, build failures (output directory/build script/function pattern/config conflict), dynamic-route 404s, environment variables not taking effect, cold starts, and Edge Config connection errors — the causes and fix procedures.

- Published: 2026-06-28
- Author: 友田 陽大
- Tags: Vercel, Next.js, 可観測性, インフラ, CI/CD, TypeScript, パフォーマンス
- URL: https://tomodahinata.com/en/blog/vercel-troubleshooting-build-function-errors-timeout-guide
- Category: Vercel in production
- Pillar guide: https://tomodahinata.com/en/blog/vercel-production-platform-guide

## Key points

- Narrow Vercel errors by category — 'function, deployment/build, routing, request, configuration.' First pinpoint the symptom with Observability and Runtime Logs, then reverse-look-up from the error code.
- FUNCTION_INVOCATION_TIMEOUT(504) is a maxDuration overrun. Separate long-running processing into Workflows/a queue, and return the initial response with streaming. Understand the default 300s and Pro/Ent max 800s.
- FUNCTION_PAYLOAD_TOO_LARGE(413) is a request/response body over 4.5MB. Send uploads directly to Blob with client upload, bypassing the function. FALLBACK_BODY_TOO_LARGE is an ISR page over 20MB — make the page output lighter.
- Frequent build failures are 'wrong output directory/build script,' 'function pattern mismatch (outside the api directory),' 'functions and builds config conflict,' and 'route path-to-regexp syntax error.' Reproduce the same build command locally to isolate.
- Environment-variable changes apply only to a new deployment (existing ones don't change). Without NEXT_PUBLIC_ it won't appear in the browser. For dynamic-route 404s, check generateStaticParams, the dynamic setting, and the custom domain's DNS.

---

When a 504, 413, or build failure appears in production, you panic. But Vercel errors have **mostly fixed categories and causes**, so you can crush them quickly with a reverse look-up. This article, faithful to [Vercel's official error list](https://vercel.com/docs/errors) and [Functions limitations](https://vercel.com/docs/functions/limitations), is a practical collection organizing **the errors that really appear in the field, by cause.**

For the big picture, see the [Vercel production-operations guide](/blog/vercel-production-platform-guide).

---

## First: pinpoint the symptom (don't guess)

When you see an error code, before fixing blindly, **take primary-source information from the logs.**

1. **Observability tab**: pinpoint which route is raising the error rate/latency ([observability](/blog/vercel-observability-monitoring-speed-insights-log-drains-guide)).
2. **Runtime Logs**: check the relevant function's logs and stack trace.
3. **Build Logs**: build failures all appear here.
4. **`x-vercel-cache` / response headers**: the state of caching and routing.

Errors fall into roughly **5 categories.**

| Category | Representative code | Where it appears |
|---|---|---|
| Function | `FUNCTION_INVOCATION_TIMEOUT`(504), `FUNCTION_PAYLOAD_TOO_LARGE`(413), `FUNCTION_INVOCATION_FAILED`(500) | At runtime |
| Deployment/build | Missing public directory, Missing build script, `FALLBACK_BODY_TOO_LARGE` | At build time |
| Routing | Dynamic-route 404, Invalid route source pattern | At request time |
| Request | Body overrun, auth/protection | At the entrance |
| Configuration | functions vs builds conflict, invalid Edge Config connection string | At deploy time |

---

## Function errors

### FUNCTION_INVOCATION_TIMEOUT (504)

**Cause**: the function didn't complete within `maxDuration` (default 300s, Pro/Ent max 800s). Typical of long synchronous processing, infinite waits, or external-API hangs.

**Fix**:

```ts
// ① まず maxDuration を用途に合わせて明示（だらだら生かさない）
export const maxDuration = 60;

// ② 長時間処理は関数に抱えず Workflows / キューへ分離
//    （数分を超える処理を同期HTTPで持たない）
export async function POST(request: Request) {
  const job = await enqueueHeavyJob(await request.json()); // すぐ返す
  return Response.json({ jobId: job.id }, { status: 202 });
}

// ③ 進捗を返したいならストリーミングで初動を速く
```

Attach **a timeout and AbortController** to external API calls to cut hangs yourself. For separating heavy processing, see the [Functions guide](/blog/vercel-functions-fluid-compute-streaming-cron-guide).

### FUNCTION_PAYLOAD_TOO_LARGE (413)

**Cause**: the request body or response body exceeded **4.5MB.** Typical of receiving file uploads in a function.

**Fix**: send uploads **directly to Vercel Blob (client upload)**, bypassing the function.

```ts
// 旧：関数で multipart を受ける → 4.5MB で死ぬ
// 新：client upload でブラウザから Blob へ直接（転送課金も回避）
import { upload } from "@vercel/blob/client";
const blob = await upload(file.name, file, {
  access: "public",
  handleUploadUrl: "/api/upload", // トークン発行＋認可だけサーバーで
});
```

Details in the [storage/Blob guide](/blog/vercel-storage-blob-edge-config-marketplace-guide). For a large response, change to paging, streaming, or delivery via Blob.

### FALLBACK_BODY_TOO_LARGE (ISR page too large)

**Cause**: when an ISR/prerender response exceeds **20MB**, the page doesn't render in production. Caused by huge embedded data, inline images, or redundant JSON.

**Fix**: make the page output lighter. Fetch data in splits / lazy-load, externalize images with [next/image](/blog/vercel-image-optimization-next-image-cost-performance-guide), and trim unnecessary inline JSON.

### FUNCTION_INVOCATION_FAILED (500)

**Cause**: an uncaught exception inside the function. DB connection failure, unset env, null reference, etc.

**Fix**: check the stack trace in Runtime Logs. Catch exceptions at the boundary and return **a meaningful error** instead of a 500. Since unset env is common, [validate required env with Zod](/blog/nextjs-env-secret-leak-prevention-public-vars-guide) at startup.

---

## Build failures

For build failures, **the cause all appears in Build Logs.** Frequent ones, by cause.

### Wrong output directory / build script

> Missing public directory / Missing build script

**Cause**: the output directory is wrong, there's no `build` script, or the root directory (monorepo) is misspecified.

**Fix**:

- Check **Output Directory / Build Command / Root Directory** in Project Settings.
- **Run the same build command locally** and confirm the artifact is generated in the output location (the fastest isolation).
- For a monorepo, set Root Directory to the app's path.

### Function pattern mismatch / config conflict

> Unmatched function pattern / Conflicting functions and builds

**Cause**: the `functions` glob in `vercel.json` doesn't match files under `api/`, or you're **using `functions` and `builds` together** (not allowed).

**Fix**:

```json
// ❌ api/ 外を指している
{ "functions": { "users/**/*.js": { "maxDuration": 30 } } }

// ✅ api/ 配下を指す（Next.js は pages/api/** も可）
{ "functions": { "api/users/**/*.js": { "maxDuration": 30 } } }
```

Use only one of `functions` or `builds`. As a rule, use `functions` (which allows memory settings, etc.). In Next.js, what you can set in `functions` is only `memory` and `maxDuration` (the rest is auto-managed by Next.js).

### Route syntax error

> Invalid route source pattern

**Cause**: `source`/`rewrites`/`redirects` in `vercel.json` are **path-to-regexp** syntax, not raw regex. A negative lookahead must be wrapped in a group.

```json
// ❌ "source": "/feedback/(?!general)"
// ✅ "source": "/feedback/((?!general).*)"
```

### Dependency/package-manager inconsistency

**Cause**: `ERR_PNPM_UNSUPPORTED_ENGINE` (`engines.pnpm` mismatch), a lockfile-vs-package-manager mismatch, or a Node version difference.

**Fix**: align `engines`/`packageManager` in `package.json`, or enable Corepack. Node is **24 LTS by default** (18 is deprecated). Put `@vercel/speed-insights`/`@vercel/analytics` in the **`package.json` dependencies, not global** (a frequent monorepo issue).

---

## Routing and 404

### A dynamic route returns 404

**Cause**: `generateStaticParams` doesn't return the target, the `dynamic`/`dynamicParams` setting, or a path that doesn't exist at build time.

**Fix**:

```ts
// 事前生成しないパスもオンデマンドで通す
export const dynamicParams = true; // 既定 true（false だと未生成は404）

export async function generateStaticParams() {
  // 少なくとも代表パスを返す。残りはオンデマンド生成（ISR）
  return (await getPopularSlugs()).map((slug) => ({ slug }));
}
```

For ISR behavior, the [caching/ISR guide](/blog/vercel-caching-isr-cache-components-ppr-guide).

### Doesn't display on a custom domain / DNS

**Cause**: DNS records (A/CNAME) unset, awaiting propagation, or the domain isn't added.

**Fix**: confirm the necessary records with `vercel domains inspect <domain>`. Keeping the TTL short speeds up switching/confirmation.

---

## Environment variables "don't take effect"

This isn't an error but **a sticking point**, and there are very many consultations about it.

- **Environment-variable changes apply only to a new deployment.** The existing production deployment doesn't change → **redeploy.**
- To read it in the browser (client), the **`NEXT_PUBLIC_` prefix** is needed. Conversely, don't attach it to secrets.
- Set the value per environment (production/preview/development). If unset on preview, only preview falls over.
- An invalid Edge Config connection string (`Invalid Edge Config connection string`) means the `EDGE_CONFIG` env is stale/deleted → update it.

Details in the [environment-variables/secrets guide](/blog/vercel-environment-variables-secrets-oidc-management-guide).

---

## Cold start / slow

**Cause**: heavy function initialization (large dependencies, heavy work at startup), or the function executes every time on a cache miss.

**Fix**:

- With **Fluid Compute** (default), concurrency and pre-warming work, and Node 20+'s bytecode cache works.
- Do heavy startup work (large JSON parse, connection establishment) once outside the handler / lazily.
- **Don't call the function in the first place** — make it a `HIT` with the ISR/CDN cache ([caching](/blog/vercel-caching-isr-cache-components-ppr-guide)). Confirm with `x-vercel-cache`.
- Trim the bundle (remove unnecessary dependencies, 250MB limit).

---

## Trouble-isolation checklist

- [ ] Took primary-source information from **Observability / Runtime Logs / Build Logs** (don't guess)
- [ ] 504 → make `maxDuration` explicit + **separate** long-running processing, timeout external APIs
- [ ] 413 → uploads are **client upload directly to Blob**
- [ ] ISR over 20MB → lighten the page output
- [ ] Build failure → **reproduce the same build locally**, check output location/route/function pattern
- [ ] 404 → `generateStaticParams`/`dynamicParams`, DNS
- [ ] env not taking effect → **redeploy**, `NEXT_PUBLIC_`, per-environment settings
- [ ] Slow → `HIT` with caching, Fluid, bundle reduction

---

## Conclusion

Vercel troubleshooting can be crushed mechanically with "**pinpoint the symptom with logs → category → cause → standard fix.**"

1. **Logs, not guessing** (Observability / Runtime / Build Logs)
2. **504 is separation, 413 is direct-to-Blob, ISR 20MB is lightening**
3. **Build failures are local reproduction** to isolate
4. **env is redeploy, `NEXT_PUBLIC_`, per-environment settings**
5. **Cure slowness with cache HIT**

I accompany you as a project through production incident investigation, permanent measures, and building out recurrence prevention. I also take spot investigations starting from the "an unexplained 504/500 is appearing" stage.

> This article is based on the official documentation of the [Vercel error list](https://vercel.com/docs/errors) / [Functions limitations](https://vercel.com/docs/functions/limitations) (as of June 2026). Error codes and limits get updated, so confirm the latest in the official docs.
