Fix Vercel “FUNCTION_INVOCATION_FAILED” 500 errors
Explore with AI
FUNCTION_INVOCATION_FAILED Vercel returns this 500 Internal Server Error when the process running your function crashes, most often because Node.js or Bun hit an uncaught exception or an unhandled promise rejection. Open the request in runtime logs to read the stack trace, then fix the throw: usually a missing environment variable, a file left out of the function bundle, or a function running out of memory.
On this page
- What FUNCTION_INVOCATION_FAILED means
- Finding the crash in Vercel’s runtime logs
- Cause 1: an uncaught exception or unhandled promise rejection
- Cause 2: an environment variable that’s missing at runtime
- Cause 3: a file or dependency traced out of the function bundle
- Cause 4: the function runs out of memory
- How to confirm FUNCTION_INVOCATION_FAILED is fixed
- Stopping crashes from coming back
- Tracing FUNCTION_INVOCATION_FAILED to its cause with Polylane
- Common questions
You see this code on Vercel’s 500 page, in the Logs tab next to a red 5xx row, or in a client that got an empty Internal Server Error back from an API route. It can hit one route or every route that imports the same broken module. It often starts right after a deploy that worked fine on your machine.
The code itself says very little. It tells you the function process died before it sent a response. The reason is almost always printed one line above it in your runtime logs, as a stack trace. This page shows how to get to that line fast, and how to fix the four causes that produce it most often.
What FUNCTION_INVOCATION_FAILED means
Vercel’s error reference defines it as a failed function invocation, with status code 500 and the name Internal Server Error. It lists two possible causes:
- The runtime process (Node.js, Bun, Python and so on) crashed.
- Node.js or Bun threw an unhandled rejection or an uncaught exception.
Vercel files it under function errors. The platform did its job: it routed the request to your function and started it. Your code, or the environment it runs in, then failed hard enough to take the process down.
That makes it different from the timeout codes. A function that runs too long fails with FUNCTION_INVOCATION_TIMEOUT and a 504. If that’s what you’re seeing, read how to debug Vercel function timeouts and the guide to the 504 gateway timeout on serverless functions. This page covers crashes only.
When I worked on observability for Workers at Cloudflare, most “the platform returned a 500” reports turned out to be one uncaught throw at module load. The fix starts with reading the right log line, so do that before you change any code.
Finding the crash in Vercel’s runtime logs
Runtime logs hold everything your function writes to stdout and stderr, grouped per request. Open your project, go to Logs in the sidebar, and filter by Status Code 500. Since March 2026, the request details panel also shows the specific error code next to the HTTP status, so you can confirm the row is FUNCTION_INVOCATION_FAILED and not another 500 (changelog).
The CLI does the same from a terminal:
# Production 500s from the last hour, full messages
vercel logs --environment production --status-code 500 --since 1h --expand
# Everything logged for one request
vercel logs --request-id <request-id> --expand
# Only Vercel Function logs, as JSON for jq
vercel logs --source serverless --level error --json | jq '.message'
To get the request ID for a request you made yourself, read the x-vercel-id response header. Vercel’s custom error page docs say the request ID token matches that header’s value.
In the request details, look at three things:
- Log Messages. The stack trace or error message your runtime printed just before the crash. This names the cause in most cases.
- Function. The function name, runtime, duration and memory usage for that invocation.
- Deployment. The deployment ID and branch. If the errors start at one deployment, diff that deployment against the previous one.
Act quickly on older failures. The runtime logs docs keep logs for 1 hour on Hobby, 1 day on Pro and 3 days on Enterprise, or 30 days with Observability Plus.
Cause 1: an uncaught exception or unhandled promise rejection
How to tell it’s yours: the log for the failed request ends with a stack trace from your own code or a library it calls. Typical messages are TypeError: Cannot read properties of undefined, a JSON parse error, or a rejected fetch or database call.
This is the most common cause and the first one in Vercel’s list. An exception that nothing catches ends the process. Promise rejections do the same. The Node.js CLI docs say that since Node.js 15 the default --unhandled-rejections mode is throw: Node emits unhandledRejection, and if no handler is set, it raises the rejection as an uncaught exception. So a single await without error handling, or a promise you fired and forgot, is enough to crash the function.
Fix:
- Read the top frame of the stack trace that belongs to your code. That’s the line to fix.
- Wrap the handler body in
try/catch, which is the first fix Vercel’s error reference suggests. Log the error with its stack and return a proper error response:// app/api/orders/route.ts export async function POST(request: Request) { try { const body = await request.json(); const order = await createOrder(body); return Response.json(order, { status: 201 }); } catch (err) { console.error("POST /api/orders failed", err); return Response.json({ error: "Could not create order" }, { status: 500 }); } } - Await every promise you start, or attach a
.catch()to it. A background call you don’t await can reject after the response logic has moved on:// Before: a rejection here has no handler sendWelcomeEmail(user); // After sendWelcomeEmail(user).catch((err) => { console.error("welcome email failed", err); }); - Add process-level handlers in a module every function imports, so any throw you missed is logged with its stack. Keep them for logging. They don’t replace the fixes above:
// lib/crash-logging.ts process.on("unhandledRejection", (reason) => { console.error("unhandledRejection", reason); }); process.on("uncaughtException", (err) => { console.error("uncaughtException", err); }); - Validate input before you use it. A request body that’s missing a field is a common source of
undefinederrors on one route only.
Check for throws at module load too. Code at the top level of a file, such as a client constructor that reads config, runs before your handler. If it throws, every request to that function fails, and a try/catch inside the handler can’t help. Move that setup into a function you call inside the handler, or guard it.
Cause 2: an environment variable that’s missing at runtime
How to tell it’s yours: the stack trace mentions a value that is undefined, an SDK complains that an API key or connection string is missing, or a database client fails to connect with an empty host. It works locally and in one environment, and fails in another.
Vercel scopes each environment variable to Production, Preview or Development, and optionally to a Git branch. A variable that exists in your local .env or only in Preview isn’t there in Production. The environment variables docs also say changes are not applied to previous deployments. They only apply to new ones. So adding the variable fixes nothing until you redeploy.
Fix:
- List what each environment has:
Sensitive values are hidden in this list, which is expected. Check that the name is present and spelled the same way your code reads it.vercel env ls production vercel env ls preview - Add or update the missing variable for the right environment:
vercel env add DATABASE_URL production vercel env update DATABASE_URL production - Reproduce locally with the exact production set. You can pull it to a file or run a command with it, without writing it to disk:
vercel env pull .env.production.local --environment=production vercel env run -e production -- next build - Redeploy so the function gets the new values:
vercel --prod - Fail fast with a clear message. Check required variables when the handler runs, so the log says which one is missing:
function requireEnv(name: string): string { const value = process.env[name]; if (!value) throw new Error(`Missing environment variable ${name}`); return value; }
One more limit to know. Vercel allows 64 KB of environment variables in total per deployment, and no single variable can be larger than that. A very large certificate or JSON blob can push you over it.
Cause 3: a file or dependency traced out of the function bundle
How to tell it’s yours: the log shows ENOENT: no such file or directory for a path your code reads, or Cannot find module for a package or a native binary. The same code works with next dev or vercel dev.
At build time, Vercel and Next.js trace which files each function needs and put only those in the bundle. Files read through dynamic paths, templates, fonts, data files and some native binaries can be missed. The Next.js output docs say tracing can fail to include required files, and give outputFileTracingIncludes as the fix.
Fix for Next.js:
- Add the missing files to the trace for the routes that need them. Keys are route globs and values are file globs from the project root:
// next.config.js module.exports = { outputFileTracingIncludes: { "/api/report": ["./templates/**/*"], "/*": ["./src/config/runtime/**/*.json"], }, }; - In a monorepo, files outside the Next.js project folder aren’t traced by default. Set
outputFileTracingRootand include them:const path = require("path"); module.exports = { outputFileTracingRoot: path.join(__dirname, "../../"), outputFileTracingIncludes: { "/api/report": ["../shared/assets/**/*"], }, }; - Keep patterns narrow. The Next.js docs warn against
**/*at the repo root because it makes oversized traces.
Fix for other frameworks: use includeFiles in the functions block of vercel.json. The vercel.json reference notes that it is not supported in Next.js:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"functions": {
"api/report.js": {
"includeFiles": "templates/**"
}
}
}
Then redeploy and check the build output. Vercel caps a function bundle at 250 MB uncompressed, or 500 MB for Python, per the functions limits. If adding files pushes you near that, use outputFileTracingExcludes or excludeFiles to drop what the function doesn’t use.
Cause 4: the function runs out of memory
How to tell it’s yours: the request has no useful stack trace, or the log stops mid-work. The Function section of the request details shows memory usage close to the function’s limit. Failures cluster on routes that handle large payloads, images, PDFs or big query results.
Vercel’s knowledge base guide on OOM failures says that when a function hits its memory limit, the runtime terminates it and returns a 500 error. That matches the “runtime process crashed” cause in the error reference.
Fix:
- Confirm it. Go to Observability, then Vercel Functions, pick the route, and read the Peak memory chart against the provisioned limit. The guide says a function that regularly uses 80 to 90% of its memory is at risk under traffic spikes.
- Cut the memory the request needs. Stream large responses and files, paginate big queries, and avoid loading a whole upload into memory at once.
- If the work really needs more, raise the memory. The memory docs say you can’t set memory in
vercel.json, and doing so gives a warning at build time. On Pro and Enterprise:- Open the project, then Settings, then Functions.
- Select Advanced Settings.
- Under Function CPU, switch from Standard (2 GB, 1 vCPU) to Performance (4 GB, 2 vCPUs).
- Create a new deployment. The change applies only to future deployments.
- On Hobby, memory is fixed at 2 GB with 1 vCPU, and 2 GB is also the plan’s maximum. Reducing usage is the only fix there, or moving to Pro, where the maximum is 4 GB.
How to confirm FUNCTION_INVOCATION_FAILED is fixed
After the new deployment is live:
- Call the route that failed and check for a 200 or the status you expect:
curl -s -o /dev/null -w "%{http_code}\n" https://your-app.vercel.app/api/orders - Watch for new 500s on the new deployment:
No new rows withvercel logs --environment production --status-code 500 --since 30m --expandFUNCTION_INVOCATION_FAILEDin the request details means the crash is gone. - Open Observability, select Vercel Functions, and check the Error Rate graph. Sort the routes by error rate. The route you fixed should be back at its usual baseline.
If the 500s continue but the stack trace changed, you’ve fixed one throw and found the next. Repeat from the logs.
Stopping crashes from coming back
- Keep the logging handlers.
unhandledRejectionanduncaughtExceptionlogging means the next crash arrives with a stack trace. - Check required environment variables in CI. Run the build with production variables through
vercel env run -e production -- <command>so a missing variable fails before deploy. - Test the deployed bundle. Hit every route on a Preview deployment before promoting it. Missing traced files only show up in the deployed bundle.
- Watch memory before it runs out. Review the Peak memory chart for heavy routes after each release.
- Alert on 5xx spikes. Vercel’s knowledge base guide says Vercel raises an alert when function failures cause a spike in errors on a route. Route those alerts to the channel your on-call reads, and keep your logs long enough to read them.
Tracing FUNCTION_INVOCATION_FAILED to its cause with Polylane
Polylane connects to Vercel with OAuth and can query its logs and metrics, and alerts that fire on a connected Vercel account become issues. A fix run reads the logs, recent deploys and your code, traces the crash to its cause with evidence, and opens a pull request for you to review when a code change fixes it.
Running on Vercel? See how Polylane monitors Vercel in production.
Common questions.
What status code does FUNCTION_INVOCATION_FAILED return?
It returns 500, named Internal Server Error in Vercel's error reference. Vercel classes it as a function error, so the cause sits in your function code or its environment. Filter runtime logs with vercel logs --status-code 500 to find the affected requests.
Why does my function work locally but crash on Vercel?
The two usual reasons are environment variables and files. A variable set in your local .env may not exist in the Production environment on Vercel, so check with vercel env ls production. A file your code reads at runtime may not be traced into the function bundle, which you fix with includeFiles in vercel.json or outputFileTracingIncludes in next.config.js.
I added the missing environment variable. Why do I still get the error?
Vercel applies environment variable changes only to new deployments. The deployment that is crashing still has the old set of variables. Redeploy after you add or update the variable, then check the new deployment's logs.
Can I raise function memory in vercel.json?
No. Vercel's memory docs say memory can't be set in vercel.json, and you get a warning at build time if you try. On Pro and Enterprise, change it under Settings, Functions, Advanced Settings, Function CPU: Standard is 2 GB with 1 vCPU and Performance is 4 GB with 2 vCPUs. Hobby always runs with 2 GB.
Does an unhandled promise rejection really crash the function?
Yes, on any current Node.js version. Since Node.js 15 the default --unhandled-rejections mode is throw, which raises an unhandled rejection as an uncaught exception when no unhandledRejection handler is set. Vercel's error reference lists that as one of the two causes of FUNCTION_INVOCATION_FAILED.
How long do I have to read the runtime logs for a failed request?
Runtime logs are kept for 1 hour on Hobby, 1 day on Pro and 3 days on Enterprise. Observability Plus on Pro or Enterprise extends that to 30 days. Each request can log up to 256 lines and 1 MB in total, so log the error once with its stack trace.
Is FUNCTION_INVOCATION_FAILED the same as a timeout?
No. A function that runs past its maximum duration fails with FUNCTION_INVOCATION_TIMEOUT and a 504 status. FUNCTION_INVOCATION_FAILED is a 500 and means the process crashed or threw before it could send a response.
Where do I find the request ID for a failed request?
Every Vercel response carries an x-vercel-id header, and Vercel's custom error page docs say the request ID token matches that header's value. Each row in the Logs tab also shows the request ID. Pass it to vercel logs --request-id to pull every log line for that one request.
Sources
- FUNCTION_INVOCATION_FAILED (Vercel Docs)
- FUNCTION_INVOCATION_TIMEOUT (Vercel Docs)
- vercel deploy (Vercel CLI Docs)
- Runtime Logs (Vercel Docs)
- vercel logs (Vercel CLI Docs)
- View specific error codes in runtime logs (Vercel Changelog)
- vercel env (Vercel CLI Docs)
- Environment Variables (Vercel Docs)
- Configuring Memory and CPU for Vercel Functions (Vercel Docs)
- Vercel Functions Limits (Vercel Docs)
- Static Configuration with vercel.json (Vercel Docs)
- Detect memory and OOM failures in Vercel Functions (Vercel Knowledge Base)
- Observability (Vercel Docs)
- Custom error pages (Vercel Docs)
- output: outputFileTracingIncludes (Next.js Docs)
- --unhandled-rejections (Node.js CLI Docs)
- Polylane documentation
- Polylane full content
Boris Tane is the founder of Polylane. He previously founded Baselime, observability for the future of the cloud, which Cloudflare acquired. At Cloudflare he built and led the Workers observability team.
Related
- How to debug Vercel function timeouts
Debug Vercel FUNCTION_INVOCATION_TIMEOUT 504s: find the slow call with vercel logs and httpstat, fix hangs, set maxDuration and verify on a preview.
- Vercel 504 Gateway Timeout on Serverless Functions: Causes and Fixes
Fix Vercel 504 FUNCTION_INVOCATION_TIMEOUT errors: current duration limits, how to find the slow call, the fix for each cause and how to raise maxDuration.
- Fix Vercel “MIDDLEWARE_INVOCATION_FAILED” errors
Why Vercel returns 500 MIDDLEWARE_INVOCATION_FAILED or EDGE_FUNCTION_INVOCATION_FAILED, how to find the failing middleware in logs, and how to fix it.
- Fix Prisma “P1001: Can't reach database server”
Why Prisma prints “P1001: Can't reach database server”, how to test the host and port it names, and how to fix private hosts, IPv6, paused databases and URLs.
- Fix Railway “Application failed to respond” (502)
Why Railway returns “Application failed to respond” with a 502, how to tell a wrong host, port or target port from a crash or overload, and how to fix each.