{"record":{"id":"b7490bf2036eff9b","repo":"denoland/deno","slug":"cannot-change-headers-headers-are-immutable","errorCode":null,"errorMessage":"Cannot change headers: headers are immutable","messagePattern":"Cannot change headers: headers are immutable","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/20_headers.js","lineNumber":467,"sourceCode":"    name = webidl.converters[\"ByteString\"](name, prefix, \"Argument 1\");\n    value = webidl.converters[\"ByteString\"](value, prefix, \"Argument 2\");\n    appendHeader(this, name, value);\n  }\n\n  /**\n   * @param {string} name\n   */\n  delete(name) {\n    webidl.assertBranded(this, HeadersPrototype);\n    const prefix = \"Failed to execute 'delete' on 'Headers'\";\n    webidl.requiredArguments(arguments.length, 1, prefix);\n    name = webidl.converters[\"ByteString\"](name, prefix, \"Argument 1\");\n\n    if (!checkHeaderNameForHttpTokenCodePoint(name)) {\n      throw new TypeError(`Invalid header name: \"${name}\"`);\n    }\n    if (this[_guard] == \"immutable\") {\n      throw new TypeError(\"Cannot change headers: headers are immutable\");\n    }\n\n    const list = headerListFromHeaders(this);\n    const lowerNames = ensureLowerNames(this);\n    const lowercaseName = byteLowerCase(name);\n    let writeIdx = 0;\n    for (let i = 0; i < lowerNames.length; i++) {\n      if (lowerNames[i] !== lowercaseName) {\n        list[writeIdx] = list[i];\n        lowerNames[writeIdx] = lowerNames[i];\n        writeIdx++;\n      }\n    }\n    if (writeIdx !== list.length) {\n      ArrayPrototypeSplice(list, writeIdx);\n      ArrayPrototypeSplice(lowerNames, writeIdx);\n    }\n  }","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/fetch/20_headers.js#L449-L485","documentation":"Headers.prototype.delete() throws when this[_guard] == \"immutable\". Per the Fetch spec, the headers of a Response returned by fetch() are guarded \"immutable\", so every mutating method (delete/set/append) is rejected even if the name itself is valid. The name check runs first, so a valid name on a fetched response's headers always hits this guard.","triggerScenarios":"const res = await fetch(url); res.headers.delete(\"x-foo\"); - or res.headers.delete(...) inside a proxy/middleware that tries to strip hop-by-hop headers from an upstream response.","commonSituations":"Middleware that strips CORS or cache headers from fetch() responses; retry wrappers that want to remove stale headers before returning; code ported from Node/http where response headers were a plain mutable map.","solutions":["Copy into a fresh mutable Headers and mutate the copy: const h = new Headers(res.headers); h.delete(\"x-foo\")","Build a new Response with the modified headers: new Response(res.body, { status, headers: newHeaders }) and return that","Read values from res.headers (get/has/entries are allowed) and only ever write to headers you constructed yourself"],"exampleFix":"// before\nconst res = await fetch(url);\nres.headers.delete(\"x-cache\"); // TypeError: immutable\n\n// after\nconst res = await fetch(url);\nconst headers = new Headers(res.headers);\nheaders.delete(\"x-cache\");\nconst out = new Response(res.body, { status: res.status, headers });","handlingStrategy":"fallback","validationCode":"const mutable = new Headers(res.headers); // copies content, guard resets to \"none\"\nmutable.delete(\"x-foo\");","typeGuard":null,"tryCatchPattern":"try { res.headers.delete(name); } catch (e) {\n  if (e instanceof TypeError && e.message.includes(\"headers are immutable\")) {\n    const h = new Headers(res.headers); h.delete(name); return h;\n  }\n  throw e;\n}","preventionTips":["Assume every header object you did not construct with new Headers() is read-only","Route all header mutations through a helper that copies first, mutates the copy","Return new Response(res.body, { headers }) instead of editing fetched responses"],"tags":["fetch","headers","immutability"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}