{"record":{"id":"568b16acec067797","repo":"sveltejs/kit","slug":"key-header-is-already-set","errorCode":null,"errorMessage":"\"${key}\" header is already set","messagePattern":"\"(.+?)\" header is already set","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/kit/src/runtime/server/respond.js","lineNumber":225,"sourceCode":"\t\tsetHeaders: (new_headers) => {\n\t\t\tif (DEV) {\n\t\t\t\tvalidateHeaders(new_headers);\n\t\t\t}\n\n\t\t\tfor (const key in new_headers) {\n\t\t\t\tconst lower = key.toLowerCase();\n\t\t\t\tconst value = new_headers[key];\n\n\t\t\t\tif (lower === 'set-cookie') {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Use `event.cookies.set(name, value, options)` instead of `event.setHeaders` to set cookies'\n\t\t\t\t\t);\n\t\t\t\t} else if (lower in headers) {\n\t\t\t\t\t// appendHeaders-style for Server-Timing https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing\n\t\t\t\t\tif (lower === 'server-timing') {\n\t\t\t\t\t\theaders[lower] += ', ' + value;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Error(`\"${key}\" header is already set`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\theaders[lower] = value;\n\n\t\t\t\t\tif (state.prerendering && lower === 'cache-control') {\n\t\t\t\t\t\tstate.prerendering.cache = /** @type {string} */ (value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\turl,\n\t\tisDataRequest: is_data_request,\n\t\tisSubRequest: state.depth > 0,\n\t\tisRemoteRequest: !!remote_id\n\t};\n\n\t// @ts-expect-error this has to be assigned lazily\n\tevent.fetch = create_fetch({","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/sveltejs/kit/blob/03f1687fe612ce3d2d9131139b5b188d9cf90c64/packages/kit/src/runtime/server/respond.js#L207-L243","documentation":"SvelteKit stores response headers keyed by lowercase name. When you call event.setHeaders() (or set a header in an endpoint response) with a header name that maps to a lowercase key already present, it throws instead of silently overwriting — except for Server-Timing, which is appended per spec. This prevents accidental double-setting of headers like content-type or cache-control.","triggerScenarios":"Calling event.setHeaders({ 'Content-Type': 'x' }) in load and also returning a Response with a content-type header; calling setHeaders twice with the same (case-insensitive) header in a handle hook and in load; setting a header in +layout.js load and again in +page.js load.","commonSituations":"A handle hook adds security headers globally while a page also sets the same header; migrating an endpoint from returning a plain object with headers to setHeaders; framework upgrade made duplicate-header collisions throw instead of being ignored.","solutions":["Find the code path setting the duplicate header (hook vs load vs endpoint) and remove one of the two setHeaders calls","Use case-consistent naming and centralize header setting in src/hooks.server.js so it happens only once","If appending is intended (e.g. timing), use the Server-Timing header which is concatenated, or merge values into a single comma-separated string yourself"],"exampleFix":"// before (hooks.server.js + page both set it)\nexport const handle = async ({ event, resolve }) => { event.setHeaders({ 'x-frame-options': 'DENY' }); return resolve(event); };\n// in +page.server.js\nevent.setHeaders({ 'X-Frame-Options': 'DENY' });\n// after\nexport const handle = async ({ event, resolve }) => { event.setHeaders({ 'x-frame-options': 'DENY' }); return resolve(event); };\n// removed duplicate setHeaders in +page.server.js","handlingStrategy":"validation","validationCode":"function canSetHeader(headers, key) {\n  return !(key.toLowerCase() in headers) || key.toLowerCase() === 'server-timing';\n}\n// usage: if (canSetHeader(existing, 'x-frame-options')) event.setHeaders({ 'x-frame-options': 'DENY' });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set global headers once in src/hooks.server.js","Use lowercase header names consistently to spot duplicates early","Treat Server-Timing as the only append-style header"],"tags":["http-headers","sveltekit","server"],"backgroundTag":"duplicate-http-header-set","analyzedSha":"03f1687fe612ce3d2d9131139b5b188d9cf90c64","analyzedAt":"2026-09-02T02:01:50.504Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}