{"record":{"id":"d9a809ffa0e86c82","repo":"remix-run/react-router","slug":"missing-body-in-server-response","errorCode":null,"errorMessage":"Missing body in server response","messagePattern":"Missing body in server response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/react-router/lib/rsc/server.ssr.tsx","lineNumber":127,"sourceCode":"  hydrate?: boolean;\n  nonce?: string;\n}): Promise<Response> {\n  const url = new URL(request.url);\n  const isDataRequest = isReactServerRequest(url);\n  const respondWithRSCPayload =\n    isDataRequest ||\n    isManifestRequest(url) ||\n    request.headers.has(\"rsc-action-id\");\n\n  if (\n    respondWithRSCPayload ||\n    serverResponse.headers.get(\"React-Router-Resource\") === \"true\"\n  ) {\n    return serverResponse;\n  }\n\n  if (!serverResponse.body) {\n    throw new Error(\"Missing body in server response\");\n  }\n\n  const detectRedirectResponse = serverResponse.clone();\n\n  let serverResponseB: Response | null = null;\n  if (hydrate) {\n    serverResponseB = serverResponse.clone();\n  }\n\n  const body = serverResponse.body;\n\n  let buffer: Uint8Array[] | undefined;\n  let streamControllers: ReadableStreamDefaultController<Uint8Array>[] = [];\n\n  const createStream = () => {\n    if (!buffer) {\n      buffer = [];\n      return body.pipeThrough(","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/remix-run/react-router/blob/7aea711dd1ae2bc5a076d13ff17291829690fa74/packages/react-router/lib/rsc/server.ssr.tsx#L109-L145","documentation":"In the RSC SSR server pipeline, once a request is identified as a normal document (HTML) request — not a data, manifest, or RSC-action request, and not one where the handler already returned an RSC resource response — the returned server `Response` must have a body so the server can decode it, detect redirects, and build the HTML shell. A bodyless response at this point is treated as a programming error in the request handler and throws.","triggerScenarios":"A custom `handleRequest`/middleware returning `new Response(null, { status: 204 })` or any `Response` with a null body for document requests; returning the same `Response` object after its stream was already consumed elsewhere; redirect helpers misused so a bodyless 3xx reaches the document pipeline.","commonSituations":"Writing custom framework-mode server entries or middleware that short-circuit with empty responses; adapting express/cloudflare adapters that construct bare `Response` objects; middleware that returns `next()` results after reading them.","solutions":["Make every document-request code path return a Response with a real body (HTML string or stream), or use the framework's redirect utilities instead of hand-built bodyless responses.","If you must return an empty status (e.g., 204), scope it to non-document requests or set `React-Router-Resource: true` handling appropriately so it bypasses the HTML pipeline.","Ensure middleware returns a fresh Response when it has consumed the original body.","Log `response.status`/`response.body` in your handler before returning to find the offending branch."],"exampleFix":"// before (custom handleRequest)\nif (isBlocked) {\n  return new Response(null, { status: 204 });\n}\n\n// after\nif (isBlocked) {\n  return new Response(\"<html><body>Blocked</body></html>\", {\n    status: 403,\n    headers: { \"content-type\": \"text/html\" },\n  });\n}","handlingStrategy":"validation","validationCode":"// in a custom handleRequest, before returning\nif (!response.body && !request.headers.has(\"rsc-action-id\")) {\n  return new Response(\"<html><body>Empty response</body></html>\", {\n    status: 200,\n    headers: { \"content-type\": \"text/html\" },\n  });\n}\nreturn response;","typeGuard":"const hasBody = (res: Response): boolean => res.body != null;","tryCatchPattern":null,"preventionTips":["Never return bodyless Responses from document-request handlers or middleware.","Use the framework's redirect helpers instead of hand-constructed 3xx Responses.","Unit-test custom middleware paths to assert every branch returns a bodied Response."],"tags":["rsc","ssr","response-body","custom-server","middleware"],"backgroundTag":"empty-response-body","analyzedSha":"7aea711dd1ae2bc5a076d13ff17291829690fa74","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}