{"record":{"id":"620cd2daea185186","repo":"withastro/astro","slug":"responsesenterror-620cd2","errorCode":"ResponseSentError","errorMessage":"The response has already been sent to the browser and cannot be altered.","messagePattern":"The response has already been sent to the browser and cannot be altered\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/runtime/server/render/astro/render.ts","lineNumber":96,"sourceCode":"\n\treturn new ReadableStream({\n\t\tstart(controller) {\n\t\t\tconst destination: RenderDestination = {\n\t\t\t\twrite(chunk) {\n\t\t\t\t\t// Automatic doctype insertion for pages\n\t\t\t\t\tif (isPage && !renderedFirstPageChunk) {\n\t\t\t\t\t\trenderedFirstPageChunk = true;\n\t\t\t\t\t\tif (!result.partial && !DOCTYPE_EXP.test(String(chunk))) {\n\t\t\t\t\t\t\tconst doctype = result.compressHTML ? '<!DOCTYPE html>' : '<!DOCTYPE html>\\n';\n\t\t\t\t\t\t\tcontroller.enqueue(encoder.encode(doctype));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// `chunk` might be a Response that contains a redirect,\n\t\t\t\t\t// that was rendered eagerly and therefore bypassed the early check\n\t\t\t\t\t// whether headers can still be modified. In that case, throw an error\n\t\t\t\t\tif (chunk instanceof Response) {\n\t\t\t\t\t\tthrow new AstroError({\n\t\t\t\t\t\t\t...AstroErrorData.ResponseSentError,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst bytes = chunkToByteArray(result, chunk);\n\t\t\t\t\tcontroller.enqueue(bytes);\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t(async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait renderStreaming(templateResult, result, destination);\n\t\t\t\t\tcontroller.close();\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// We don't have a lot of information downstream, and upstream we can't catch the error properly\n\t\t\t\t\t// So let's add the location here\n\t\t\t\t\tif (AstroError.is(e) && !e.loc) {\n\t\t\t\t\t\te.setLocation({","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/runtime/server/render/astro/render.ts#L78-L114","documentation":"In streaming (ReadableStream) rendering, once the first chunk is enqueued the status/headers are committed to the client and can no longer change. If a Response object (typically a redirect produced by Astro.redirect) is rendered eagerly and then reaches the stream's write path after output has flushed, Astro throws ResponseSentError instead of silently dropping the redirect.","triggerScenarios":"Returning Astro.redirect(...) (or any Response) from a layout, a slot's content, or a nested component rendered after the page's first chunk already flushed; awaiting slow data in frontmatter and returning a redirect only after streaming has begun.","commonSituations":"Auth checks placed in a layout instead of middleware or page frontmatter; redirects raised from deep inside slot content or try/catch handlers; mixing streamed rendering with control-flow Responses.","solutions":["Move redirects into page frontmatter before any markup is produced, or into middleware (onRequest / next()) where nothing has flushed","Do auth/session checks in middleware so redirects happen before render starts","Ensure components/layouts never return a Response; only pages may return one","If data may arrive late, redirect from middleware or the page's frontmatter await, not from a child component"],"exampleFix":"// before: redirect inside a layout\n---\nif (!user) return Astro.redirect('/login');\n---\n\n// after: redirect in middleware\nexport const onRequest = async (context, next) => {\n  const user = await getUser(context.request);\n  if (!user && context.url.pathname.startsWith('/dashboard')) {\n    return context.redirect('/login');\n  }\n  return next();\n};","handlingStrategy":"validation","validationCode":"// middleware: decide before anything renders\nexport const onRequest = async (context, next) => {\n  const user = await getUser(context.request);\n  if (!user && context.url.pathname.startsWith('/app')) {\n    return context.redirect('/login');\n  }\n  return next();\n};","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Return Responses only from page frontmatter or middleware — never from layouts, components, or slots","Put auth and permission checks in middleware so redirects happen before streaming starts","Await any data that might trigger a redirect before returning markup from frontmatter"],"tags":["astro","streaming","redirect","response","ssr"],"backgroundTag":"response-already-sent","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}