{"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":208,"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":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/core/cookies/cookies.ts#L190-L226","documentation":"`Astro.cookies.set()` records the outgoing cookie but then checks a `responseSent` symbol on the request; if the response has already been flushed to the browser, mutating cookies is impossible, so Astro throws `ResponseSentError`. This prevents silently losing a cookie the developer believed was set.","triggerScenarios":"Calling `Astro.cookies.set(...)` after `Astro.response.send(...)`/`redirect(...)`/`Response.json(...)` in the same request, or in middleware after the response body has been streamed. The check at `cookies.ts:208` fires on the next `set`.","commonSituations":"Returning early from a handler and then conditionally setting a cookie in code that runs after; calling `set` inside an `await` chain that completes after streaming started; middleware that sets cookies after `next()` streamed the body.","solutions":["Set all cookies before sending the response (before `return Astro.redirect(...)`, `Response.json(...)`, etc.).","Restructure control flow so cookie writes happen at the top of the handler.","Avoid long `await`s between setting a cookie and returning; move cookie logic earlier."],"exampleFix":"// before\nreturn Astro.redirect('/login', 302);\nAstro.cookies.set('flash', 'error'); // unreachable / post-send\n\n// after\nAstro.cookies.set('flash', 'error');\nreturn Astro.redirect('/login', 302);","handlingStrategy":"validation","validationCode":"// Set cookies before any response-sending call.\nAstro.cookies.set('k', 'v');\nreturn Astro.redirect('/next');","typeGuard":null,"tryCatchPattern":"try { Astro.cookies.set('k', 'v'); } catch (e) { if (e.code === 'ResponseSentError') { /* too late; log */ } else throw e; }","preventionTips":["Set cookies at the top of the handler before returning.","Avoid awaits between setting cookies and sending the response.","In middleware, set cookies before calling next()."],"tags":["cookies","runtime","response-lifecycle"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}