{"record":{"id":"25602c345dadfad6","repo":"withastro/astro","slug":"responsesenterror","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/core/cookies/cookies.ts","lineNumber":210,"sourceCode":"\t\t}\n\n\t\tconst { encode, ...attributes } = options ?? {};\n\n\t\tthis.#ensureOutgoingMap().set(key, [\n\t\t\tserializedValue,\n\t\t\tstringifySetCookie(\n\t\t\t\t{\n\t\t\t\t\t...attributes,\n\t\t\t\t\tname: key,\n\t\t\t\t\tvalue: serializedValue,\n\t\t\t\t},\n\t\t\t\t{ encode },\n\t\t\t),\n\t\t\ttrue,\n\t\t]);\n\n\t\tif ((this.#request as any)[responseSentSymbol]) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...AstroErrorData.ResponseSentError,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Merges a new AstroCookies instance into the current instance. Any new cookies\n\t * will be added to the current instance, overwriting any existing cookies with the same name.\n\t */\n\tmerge(cookies: AstroCookies) {\n\t\tconst outgoing = cookies.#outgoing;\n\t\tif (outgoing) {\n\t\t\tfor (const [key, value] of outgoing) {\n\t\t\t\tthis.#ensureOutgoingMap().set(key, value);\n\t\t\t}\n\t\t}\n\t}\n","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/withastro/astro/blob/e294953aa8aadd98d5be92e60a03037b05dbdfd4/packages/astro/src/core/cookies/cookies.ts#L192-L228","documentation":"`Astro.cookies.set()` serializes the cookie into the outgoing map, then checks the internal `Symbol.for('astro.responseSent')` flag on the request. Once the response pipeline has marked that flag (in `prepare-response` or the dev server), headers can no longer be altered and `set()` throws `ResponseSentError`. A mere `console.warn` fires when cookies were consumed (e.g. set inside an imported component); the throw is specifically for after the response was actually sent.","triggerScenarios":"Calling `Astro.cookies.set()` after returning/redirecting (e.g. after `return Astro.redirect('/login')`), inside a component rendered after headers flushed, or during streaming when the body has already started and some awaited code then sets a cookie.","commonSituations":"Login/auth flows that set a session cookie after the redirect statement; cookie logic placed in a layout or imported component instead of the page frontmatter; slow async work in a streamed page that tries to set cookies at the end.","solutions":["Move `Astro.cookies.set()` before any `return`/`Astro.redirect()` in the same frontmatter block.","Set cookies in middleware (`onRequest`) or in the page frontmatter — never in imported components or slots.","If the value only becomes known late, restructure the route: do the async work first, then set the cookie, then return the response.","As a last resort in library code, catch the error and degrade to logging instead of crashing the render."],"exampleFix":"// before — set() runs after the redirect response was sent\nif (!user) return Astro.redirect('/login');\nAstro.cookies.set('lastPath', Astro.url.pathname); // throws ResponseSentError\n\n// after — set cookies before returning the response\nAstro.cookies.set('lastPath', Astro.url.pathname);\nif (!user) return Astro.redirect('/login');","handlingStrategy":"type-guard","validationCode":"// Mirror the internal flag Astro sets on the request once the response leaves\nconst responseSent = Reflect.get(Astro.request as object, Symbol.for('astro.responseSent')) === true;\nif (!responseSent) {\n  Astro.cookies.set('session', token);\n}","typeGuard":"// True while Set-Cookie headers can still be emitted\nfunction canStillSetCookies(request: Request): boolean {\n  return Reflect.get(request, Symbol.for('astro.responseSent')) !== true;\n}","tryCatchPattern":"try {\n  Astro.cookies.set('flag', '1');\n} catch (err) {\n  if (err instanceof Error && err.name === 'ResponseSentError') {\n    logger.warn('Cookie dropped: response already sent');\n    return;\n  }\n  throw err;\n}","preventionTips":["Only call `Astro.cookies.set()` in page frontmatter or middleware `onRequest`, before any `return` or `Astro.redirect()`.","Never set cookies in imported components or layouts rendered after headers flush.","Order route code as: async work → set cookies → return response/redirect.","Test login/redirect flows in dev, which exercises the sent-response path."],"tags":["cookies","response-lifecycle","streaming","ssr"],"backgroundTag":"response-already-sent","analyzedSha":"e294953aa8aadd98d5be92e60a03037b05dbdfd4","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}