vercel/next.js · error · Error

API route returned a Response object in the Node.js runtime,

Error message

API route returned a Response object in the Node.js runtime, this is not supported. Please use `runtime: "edge"` instead: https://nextjs.org/docs/api-routes/edge-api-routes

What it means

Thrown by apiResolver() in development when a Pages Router API route (Node.js runtime) returns a Response object from its handler. The Node.js runtime for API routes does not support the web Response type; only the Edge runtime does. This is a dev-only guard (NODE_ENV !== 'production') to catch the mistake early.

Source

Thrown at packages/next/src/server/api-utils/node/api-resolver.ts:441

      opts?: {
        unstable_onlyGenerated?: boolean
      }
    ) => revalidate(urlPath, opts || {}, req, apiContext)

    const resolver = interopDefault(resolverModule)
    let wasPiped = false

    if (process.env.NODE_ENV !== 'production') {
      // listen for pipe event and don't show resolve warning
      res.once('pipe', () => (wasPiped = true))
    }

    const apiRouteResult = await resolver(req, res)

    if (process.env.NODE_ENV !== 'production') {
      if (typeof apiRouteResult !== 'undefined') {
        if (apiRouteResult instanceof Response) {
          throw new Error(
            'API route returned a Response object in the Node.js runtime, this is not supported. Please use `runtime: "edge"` instead: https://nextjs.org/docs/api-routes/edge-api-routes'
          )
        }
        console.warn(
          `API handler should not return a value, received ${typeof apiRouteResult}.`
        )
      }

      if (!externalResolver && !isResSent(res) && !wasPiped) {
        console.warn(
          `API resolved without sending a response for ${req.url}, this may result in stalled requests.`
        )
      }
    }
  } catch (err) {
    await onError?.(
      err,
      {

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Add `export const config = { runtime: 'edge' }` to the API route to switch to the Edge runtime.
  2. Or refactor the handler to use res.status().json()/res.send() instead of returning a Response.
  3. Move the logic into an App Router route handler (app/api/route.ts) which supports Response natively.

Example fix

// before (pages/api/edge-only.ts) - Node runtime returning Response
export default function handler(req, res) {
  return Response.json({ ok: true }) // throws in dev
}
// after - declare edge runtime
export const config = { runtime: 'edge' }
export default function handler(req, res) {
  return Response.json({ ok: true })
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the route declares the correct runtime before returning Response
function assertEdgeRuntime(config: { runtime?: string } | undefined) {
  if (config?.runtime !== 'edge') throw new Error('Response requires runtime: edge')
}

Type guard

function isEdgeRoute(config: any): boolean {
  return config?.config?.runtime === 'edge'
}

Prevention

When it happens

Trigger: An API route file under pages/api/ without `export const config = { runtime: 'edge' }` returns `new Response(...)` or `Response.json(...)` from its handler. At line 440 the result is checked `instanceof Response` and the error is thrown.

Common situations: Copying an Edge API route snippet into a Node API route; using fetch-like patterns that return Response; upgrading code that assumed web Response works in Node runtime.

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/ad6ca0a4e3d147d2. Report an issue: GitHub.