vercel/next.js · error · Error

Invalid response ${res.status}

Error message

Invalid response ${res.status}

What it means

Thrown during on-demand revalidation on platforms that revalidate via a network HEAD request (trustHostHeader path) when the response's cache header does not indicate 'REVALIDATED', the status is not 200, and it's not an allowed 404-onlyGenerated case. This signals the revalidation request did not succeed as expected.

Source

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

    }

    if (context.trustHostHeader) {
      const res = await fetch(`https://${req.headers.host}${urlPath}`, {
        method: 'HEAD',
        headers,
      })
      // we use the cache header to determine successful revalidate as
      // a non-200 status code can be returned from a successful revalidate
      // e.g. notFound: true returns 404 status code but is successful
      const cacheHeader =
        res.headers.get('x-vercel-cache') || res.headers.get('x-nextjs-cache')

      if (
        cacheHeader?.toUpperCase() !== 'REVALIDATED' &&
        res.status !== 200 &&
        !(res.status === 404 && opts.unstable_onlyGenerated)
      ) {
        throw new Error(`Invalid response ${res.status}`)
      }
    } else {
      throw new Error(
        `Invariant: missing internal router-server-methods this is an internal bug`
      )
    }
  } catch (err: unknown) {
    throw new Error(
      `Failed to revalidate ${urlPath}: ${isError(err) ? err.message : err}`
    )
  }
}

export async function apiResolver(
  req: IncomingMessage,
  res: ServerResponse,
  query: any,
  resolverModule: any,

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Verify the previewModeId / revalidate token matches between caller and the Next.js server.
  2. Confirm the urlPath exists and returns 200 normally (check logs for the actual status printed).
  3. Ensure the deployment supports internal revalidation or that the host header is trusted and reachable.
  4. Retry transient 5xx from the origin; investigate persistent non-200s as config mismatches.

Example fix

// before
await res.revalidate('/missing-route') // origin returns 404, not onlyGenerated
// after
await res.revalidate('/existing-route')
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the route returns 200 and the revalidate token is correct before calling res.revalidate
async function verifyRouteReachable(host: string, path: string, token: string) {
  const r = await fetch(`https://${host}${path}`, { method: 'HEAD' })
  if (r.status !== 200) throw new Error(`Route returned ${r.status} before revalidate`)
}

Try / catch

try {
  await res.revalidate(path)
} catch (err) {
  if (/Invalid response \d+/.test(err.message)) {
    // log status, verify token, then surface a user-facing error
  }
}

Prevention

When it happens

Trigger: In the trustHostHeader branch, fetch(`https://${host}${urlPath}`) returns a non-200 status whose x-vercel-cache/x-nextjs-cache is not 'REVALIDATED', and the unstable_onlyGenerated 404 exception does not apply. Causes: the origin returned 500/403/502, the revalidate secret was rejected, or the route doesn't exist.

Common situations: Incorrect PRERENDER_REVALIDATE_HEADER token; the target path returns an error; deploying without the internal router-server method (serverless + trustHostHeader) and the origin rejects the revalidation request; networking/DNS issues hitting the host.

Related errors


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