FUNCTION_INVOCATION_TIMEOUT
A Vercel Function ran past its time limit, so Vercel stopped it and returned a 504 in place of your response.
Also appears as
- Vercel Runtime Timeout Error: Task timed out after 300 seconds
Prompt to fix it
My Vercel deployment returns "504: GATEWAY_TIMEOUT" with code FUNCTION_INVOCATION_TIMEOUT on some requests. Find which route or server function times out and why. Look for slow or hanging calls (AI APIs, external APIs, database connections), code paths that never return a response, and loops. Add timeouts to outgoing requests, make every path return a response, and stream long AI responses. Raise maxDuration only for work that is legitimately long, and tell me the limit on my plan. Don’t set the maximum duration everywhere to hide the problem.
Paste into Layerwise or any AI coding tool.
What it means
API routes, server actions, and server-rendered pages on Vercel run as Vercel Functions, and each has a maximum duration. When one runs past it, Vercel stops it and sends 504: GATEWAY_TIMEOUT with this code. With Fluid compute, which new projects get by default, the limit is 300 seconds on every plan, and Pro and Enterprise can raise it to 800. Older projects without Fluid compute can stop at 10 or 15 seconds.
Most timeouts come from waiting. The function sits on something that never answers: a database connection that hangs, an AI API call that takes a minute, or a handler that never sends a response on some error path.
Raising maxDuration only helps when the work is legitimately long. Stream AI responses so users see progress, and move jobs that take minutes into the background so the page can check back later.
Common causes
- A call to an AI model or a slow external API takes longer than the function’s limit.
- A database query or connection hangs, often from a wrong connection string or an exhausted connection pool.
- A handler never sends a response, such as a Pages Router API route that skips
res.json()on an error path. - The project runs without Fluid compute, so its limit is as low as 10 seconds.
- A loop or retry loop never ends.
How to fix it
- Open Logs in the Vercel dashboard, filter by the failing route, and check how long requests ran and what they logged last.
- Give outgoing calls a timeout, such as
fetch(url, { signal: AbortSignal.timeout(30_000) }), so a stuck service fails fast with a clear error. - Make sure every code path returns a response, including error paths.
- Stream long AI responses so the response starts right away.
- If the work is legitimately long, add
export const maxDuration = 60(seconds) to the route file, and check that Fluid compute is on in the project’s Functions settings. - Move jobs that take minutes into a queue or background workflow.
Example fix
// app/api/summarize/route.ts
export const maxDuration = 60; // seconds
export async function POST(request: Request) {
const { text } = await request.json();
try {
const res = await fetch('https://api.example.com/summarize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text }),
// Fail fast instead of hanging until Vercel stops the function.
signal: AbortSignal.timeout(30_000)
});
return Response.json(await res.json(), { status: res.status });
} catch (err) {
console.error(err);
return Response.json({ error: 'Upstream request failed' }, { status: 502 });
}
}Related errors
All errors500 Internal Server Error
The server’s code threw an error or crashed while handling the request, and the real error message is waiting in the server logs.
Sorry, too many clients already
Every connection slot on the Postgres server is taken, usually by serverless functions that each open connections of their own.
Anthropic API 529 overloaded_error
Anthropic’s API had more traffic than it could serve at that moment, so it turned your request away even though the request was fine.
429 Too Many Requests
The service is rate limiting you: too many requests arrived in a short time, so it refuses more until the limit resets.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.