Next.js · sdk · fg-0308

notFound() returns HTTP 200 instead of 404 when called inside a Suspense boundary or under loading.tsx

curl -I on a missing record returns 200 OK while the page shows the not-found UI

Verified 2026-10-15 · Confirmed by 0 builders · Trust 50/100

Cause

Once a Suspense fallback or loading.tsx renders, the response headers and status are already flushed. A later notFound() or redirect() can only patch the streamed HTML, not the status line.

Fix

Call notFound() and redirect() before any await that sits under Suspense, or move the check into proxy or next.config redirects. With cacheComponents, set instant = false on the segment so it blocks instead of streaming a shell.

Apply

export const instant = false // with cacheComponents: block instead of streaming a shell

export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const item = await db.item.findUnique({ where: { id } })
  if (!item) notFound() // runs before any Suspense boundary, so the status is a real 404
  return <Item item={item} />
}

Affects: Next.js App Router 13.4 to 16.4, any route with loading.tsx or a Suspense boundary above the check

Sources

Have your agent know this before it fails

claude mcp add --transport http footgun https://getfootgun.com/api/mcp