n4nAI

Fixing 504 errors in Vercel Edge Functions with LLM calls

How to fix 504 error vercel edge function llm calls: reproduce the timeout, switch to Node runtime, stream output, add fallback, and verify with curl.

n4n Team4 min read851 words

Audio narration

Coming soon — every post will get a voice note here.

A 504 from Vercel almost always means your function exceeded its execution budget, not that the upstream model is down. To fix 504 error vercel edge function llm calls, you need to stop treating edge functions like general-purpose servers and either move the work to a longer-running Node function or stream the response so the gateway sees continuous bytes. The steps below take you from a failing deploy to a verified working route.

Step 1: Reproduce and confirm the timeout

Start by proving the 504 is a duration limit, not a code crash or an upstream 5xx. Deploy your existing edge function, then hit it with a hard client timeout shorter than the Vercel limit:

curl -i --max-time 12 https://your-app.vercel.app/api/llm

If you get 504 Gateway Timeout while the function log shows Task timed out after 10.00s, you have the classic edge ceiling. Vercel Edge Functions cap at 10 seconds of wall-clock execution regardless of plan. Note that a 502 indicates a bad gateway response from your code, while a 504 is purely the platform killing the request because the isolate didn’t return in time.

Local reproduction helps isolate config issues:

vercel dev
curl -i --max-time 12 http://localhost:3000/api/llm

Check the function logs in the Vercel dashboard under Logs > Function. Look for duration and timeout fields. If duration is pinned at 10000 ms, the platform killed the isolate. That confirmation is the baseline before you change anything.

Step 2: Understand the Edge Function constraints

Edge Functions run in a V8 isolate with no Node APIs and a hard 10s wall-clock limit. They are great for geo-distributed auth, A/B routing, or header rewriting—not for waiting on a 70B model that takes 20s to first token. A naive edge route looks like this:

// app/api/llm/route.ts (edge)
export const runtime = 'edge';

export async function POST(req: Request) {
  const res = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: { 'content-type': 'application/json', authorization: `Bearer ${process.env.OPENAI_KEY}` },
    body: JSON.stringify({ model: 'gpt-4o', messages: await req.json() }),
  });
  return new Response(await res.text());
}

This awaits the full response body. If the provider takes 11s, Vercel returns 504 and your user sees nothing. The edge runtime does not let you configure a longer timeout; the limit is architectural. To fix 504 error vercel edge function llm timeouts you must change the execution model—either move the compute or never block on a full buffer.

Step 3: Switch the route to the Node runtime

The fastest fix is to move the route off edge. In Next.js App Router, set the Node runtime and raise maxDuration:

// app/api/llm/route.ts (node)
export const runtime = 'nodejs';
export const maxDuration = 60; // seconds, Pro plan allows up to 60

export async function POST(req: Request) {
  const res = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: { 'content-type': 'application/json', authorization: `Bearer ${process.env.OPENAI_KEY}` },
    body: JSON.stringify({ model: 'gpt-4o', messages: await req.json() }),
  });
  return new Response(await res.text());
}

On Hobby, Node functions also cap at 10s, so you need a Pro account to set maxDuration above that. Redeploy and re-run the curl from Step 1 with --max-time 30. If the model responds in under 60s, the 504 disappears. This alone resolves most cases where teams search to fix 504 error vercel edge function llm deployments because they mistakenly placed a slow inference call on the edge tier.

Step 4: Stream the response to keep the connection alive

Even on Node, a 30-second silent wait can trip intermediate proxies or client fetch limits. Streaming tokens fixes that: the first byte arrives in milliseconds, and Vercel’s gateway stays happy because the TCP connection is active.

export const runtime = 'nodejs';
export const maxDuration = 60;

export async function POST(req: Request) {
  const upstream = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: { 'content-type': 'application/json', authorization: `Bearer ${process.env.OPENAI_KEY}` },
    body: JSON.stringify({ model: 'gpt-4o', stream: true, messages: await req.json() }),
  });

  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      const reader = upstream.body!.getReader();
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        controller.enqueue(value);
      }
      controller.close();
    },
  });

  return new Response(stream, { headers: { 'content-type': 'text/event-stream' } });
}

The client now receives Server-Sent Events. The function duration clock keeps running, but because bytes are flowing, no idle timeout fires. If you need to transform tokens, read the reader, decode with TextDecoder, parse the data: lines, and re-enqueue—just never buffer the entire completion before flushing.

Step 5: Add a client timeout and provider fallback

If you must stay near the edge limit, wrap the upstream call in an AbortController so a slow provider doesn’t burn your whole budget:

const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 9000); // edge-safe 9s
const res = await fetch(url, { signal: ctrl.signal, ... });
clearTimeout(t);

Better, route through a gateway that fails over automatically. For example, n4n.ai is an OpenRouter-class LLM inference gateway that performs automatic fallback when a provider is rate-limited or degraded, so a single slow endpoint won’t push you into the 504 wall. You keep one OpenAI-compatible endpoint and forward cache-control hints:

await fetch('https://api.n4n.ai/v1/chat/completions', {
  method: 'POST',
  headers: { 'content-type': 'application/json', authorization: `Bearer ${process.env.N4N_KEY}` },
  body: JSON.stringify({ model: 'anthropic/claude-3.5-sonnet', stream: true, messages }),
});

The fallback happens server-side; your edge function still sees a stream within its 10s window. This pattern also honors client routing directives if you pass them through, letting you pin a provider only when you explicitly need to.

Step 6: If you must stay on Edge, stream from the edge

Sometimes you can’t move off edge (middleware, geo logic). Then you must pipe the upstream stream without buffering. Edge runtime supports fetch and ReadableStream:

export const runtime = 'edge';

export async function POST(req: Request) {
  const upstream = await fetch('https://api.n4n.ai/v1/chat/completions', {
    method: 'POST',
    headers: { 'content-type': 'application/json', authorization: `Bearer ${process.env.N4N_KEY}` },
    body: JSON.stringify({ model: 'openai/gpt-4o', stream: true, messages: await req.json() }),
  });
  return new Response(upstream.body, { headers: { 'content-type': 'text/event-stream' } });
}

Because you never await res.text(), the isolate only spends time proxying chunks. As long as the first token arrives before 10s, the function survives. Combine with the fallback gateway from Step 5 to guarantee that the first token lands early even if the primary provider is congested.

Step 7: Verify the fix end to end

Verification is concrete. Run a timed curl against the deployed route and inspect status and headers:

curl -i --max-time 30 -X POST https://your-app.vercel.app/api/llm \
  -H 'content-type: application/json' \
  -d '{"messages":[{"role":"user","content":"ping"}]}'

You should see HTTP/2 200 and a stream of data: lines. Then check the Vercel function log: duration should be under your maxDuration and no timeout errors. If you used edge streaming, confirm duration is near the total stream time but the status is 200, proving the 504 is gone.

Finally, load test with a slow model prompt to ensure the fallback path triggers instead of a timeout. A simple loop works:

for i in {1..5}; do curl -s -o /dev/null -w "%{http_code} %{time_total}\n" --max-time 30 -X POST https://your-app.vercel.app/api/llm -d '{"messages":[{"role":"user","content":"write 500 words"}]}'; done

If every line shows 200 and a total time under your limit, you have definitively fixed the 504 error vercel edge function llm issue. The key takeaway: edge is for fast transforms, not slow generations—stream or move to Node, and let a fallback gateway absorb provider variance.

Tagsverceledge-functions504-errordebugging

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All serverless deployment debugging for llm apps posts →