{"record":{"id":"3156b2d1b99a0495","repo":"withastro/astro","slug":"astroresponseheadersreassigned","errorCode":"AstroResponseHeadersReassigned","errorMessage":"Individual headers can be added to and removed from `Astro.response.headers`, but it must not be replaced with another instance of `Headers` altogether.","messagePattern":"Individual headers can be added to and removed from `Astro\\.response\\.headers`, but it must not be replaced with another instance of `Headers` altogether\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/fetch/fetch-state.ts","lineNumber":383,"sourceCode":"\t\t\t}\n\t\t}\n\n\t\tconst componentMetadata =\n\t\t\t(await pipeline.componentMetadata(routeData)) ?? manifest.componentMetadata;\n\t\tconst headers = new Headers({ 'Content-Type': 'text/html' });\n\t\tconst partial = typeof this.partial === 'boolean' ? this.partial : Boolean(mod.partial);\n\t\tconst actionResult = hasActionPayload(this.locals)\n\t\t\t? deserializeActionResult(this.locals._actionPayload.actionResult)\n\t\t\t: undefined;\n\t\tconst status = this.status;\n\t\tconst response = {\n\t\t\tstatus: actionResult?.error ? actionResult?.error.status : status,\n\t\t\tstatusText: actionResult?.error ? actionResult?.error.type : 'OK',\n\t\t\tget headers() {\n\t\t\t\treturn headers;\n\t\t\t},\n\t\t\tset headers(_) {\n\t\t\t\tthrow new AstroError(AstroErrorData.AstroResponseHeadersReassigned);\n\t\t\t},\n\t\t} satisfies AstroGlobal['response'];\n\n\t\tconst state = this;\n\t\tconst result: SSRResult = {\n\t\t\tbase: manifest.base,\n\t\t\tuserAssetsBase: manifest.userAssetsBase,\n\t\t\tcancelled: false,\n\t\t\tclientDirectives,\n\t\t\tinlinedScripts,\n\t\t\tcomponentMetadata,\n\t\t\tcompressHTML,\n\t\t\tcookies: this.cookies,\n\t\t\tcreateAstro: (props, slots) => state.createAstro(result, props, slots, ctx),\n\t\t\tlinks,\n\t\t\t// SAFETY: createResult is only called after route resolution, so routeData\n\t\t\t// is always set and the params getter always returns a value.\n\t\t\tparams: this.params!,","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/core/fetch/fetch-state.ts#L365-L401","documentation":"`Astro.response` exposes a getter `headers` returning the live `Headers` object, but the setter is overridden to throw `AstroResponseHeadersReassigned` on any assignment. This enforces mutation-only access (`append`/`delete`/`set`) so the underlying headers instance bound to the response pipeline stays consistent; replacing it would orphan the bound headers.","triggerScenarios":"Writing `Astro.response.headers = new Headers(...)` or `Astro.response.headers = someOtherHeaders` in an `.astro` page, layout, middleware, or API route. The setter at `fetch-state.ts:383` throws immediately.","commonSituations":"Porting Express-style code that reassigns `res.headers`; misunderstanding the API and assuming `headers` is assignable; trying to swap in a pre-built `Headers` from elsewhere.","solutions":["Mutate in place: call `Astro.response.headers.set('X', 'y')`, `.append(...)`, or `.delete(...)`.","If you have a pre-built `Headers` object, iterate and `set` each entry onto `Astro.response.headers`.","Use `Astro.response.status`/`.statusText` for status changes — only `headers` is non-reassignable."],"exampleFix":"// before\nAstro.response.headers = new Headers({ 'x-cache': 'miss' });\n\n// after\nAstro.response.headers.set('x-cache', 'miss');","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Astro.response.headers is non-reassignable by contract; always mutate in place.","tryCatchPattern":"try { Astro.response.headers.set('x', 'y'); } catch (e) { if (e.code === 'AstroResponseHeadersReassigned') { /* impossible via set(); assignment was made */ } else throw e; }","preventionTips":["Never assign to Astro.response.headers; only call set/append/delete.","When porting code, translate res.headers = X into per-header set() calls.","Document the headers-mutation contract for new contributors."],"tags":["runtime","response-lifecycle","headers","api"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}