{"record":{"id":"744304aa481a09dc","repo":"denoland/deno","slug":"err-http-trailer-invalid","errorCode":"ERR_HTTP_TRAILER_INVALID","errorMessage":"Trailers are invalid with this transfer encoding","messagePattern":"Trailers are invalid with this transfer encoding","errorType":"exception","errorClass":"NodeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_http_outgoing.ts","lineNumber":1051,"sourceCode":"          this.chunkedEncoding = true;\n        } else {\n          // We should only be able to get here if both Content-Length and\n          // Transfer-Encoding are removed by the user.\n          // See: test/parallel/test-http-remove-header-stays-removed.js\n          debug(\"Both Content-Length and Transfer-Encoding are removed\");\n\n          // We can't keep alive in this case, because with no header info the body\n          // is defined as all data until the connection is closed.\n          this._last = true;\n        }\n      }\n\n      // Test non-chunked message does not have trailer header set,\n      // message will be terminated by the first empty line after the\n      // header fields, regardless of the header fields present in the\n      // message, and thus cannot contain a message body or 'trailers'.\n      if (this.chunkedEncoding !== true && state.trailer) {\n        throw new ERR_HTTP_TRAILER_INVALID();\n      }\n\n      const { header } = state;\n      this._header = header + \"\\r\\n\";\n\n      // Wait until the first body chunk, or close(), is sent to flush,\n      // UNLESS we're sending Expect: 100-continue.\n      if (state.expect) this._send(\"\");\n    },\n    writable: true,\n    enumerable: true,\n    configurable: true,\n  },\n  _storeHeaderEntry: {\n    __proto__: null,\n    value: function _storeHeaderEntry(state: any, field: string, value: any) {\n      if (ArrayIsArray(value)) {\n        // RFC 6265: join multiple Cookie values with '; '","sourceCodeStart":1033,"sourceCodeEnd":1069,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/_http_outgoing.ts#L1033-L1069","documentation":"RFC 7230 permits trailer fields only after a body that uses chunked transfer coding. During header serialization (_storeHeader) the polyfill checks `this.chunkedEncoding !== true && state.trailer` and throws ERR_HTTP_TRAILER_INVALID, because a non-chunked message ends at the first empty line after the header block and has no place to put trailers.","triggerScenarios":"Setting `res.setHeader('Trailer', 'X-Metadata')` or calling res.addTrailers() on a message that will not be chunked: serving an HTTP/1.0 client (no chunked support), a response with an explicit Content-Length (identity coding), or a message where chunkedEncoding was disabled.","commonSituations":"Testing trailer support against an HTTP/1.0 client or a server/framework that always sets Content-Length; gRPC-style metadata patterns applied to plain non-chunked responses; enabling trailers without removing Content-Length.","solutions":["Remove the Trailer header and the addTrailers() call when the transfer coding is not chunked","Let the message be chunked: keep HTTP/1.1 and do not set Content-Length (call res.removeContentLength() if a framework set it for you)","If you control the client, upgrade it to HTTP/1.1 so chunked encoding is negotiated"],"exampleFix":"// before\nres.setHeader('Content-Length', 5);\nres.setHeader('Trailer', 'X-Sum');\nres.end('hello'); // throws ERR_HTTP_TRAILER_INVALID\n\n// after (chunked)\nres.removeHeader('Content-Length');\nres.setHeader('Trailer', 'X-Sum');\nres.write('hello');\nres.addTrailers({ 'X-Sum': '5' });\nres.end();","handlingStrategy":"validation","validationCode":"// only promise trailers when the message is actually chunked\nconst canTrailer = res.chunkedEncoding === true;\nif (canTrailer) res.setHeader('Trailer', 'X-Sum');\n// ... later\nif (canTrailer) res.addTrailers({ 'X-Sum': String(sum) });","typeGuard":null,"tryCatchPattern":"try {\n  res.setHeader('Trailer', 'X-Metadata');\n  res.end(body);\n} catch (e) {\n  if (e?.code === 'ERR_HTTP_TRAILER_INVALID') {\n    res.removeHeader('Trailer');\n    res.end(body); // retry without trailers\n  } else throw e;\n}","preventionTips":["Never set Trailer together with Content-Length on the same message","Gate trailers on chunkedEncoding, which is only true for HTTP/1.1 chunked responses","Put trailer metadata in a header or the body when you cannot guarantee chunked coding"],"tags":["http","trailer","protocol","node-compat"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}