This error occurs when Node.js receives an HTTP response with malformed chunked transfer encoding. The HTTP parser cannot properly decode the response body because the chunk format violates HTTP/1.1 specifications.
This error is thrown by Node.js's HTTP parser (llhttp) when it encounters improperly formatted chunked transfer encoding in an HTTP response. Chunked transfer encoding is a mechanism where the message body is divided into chunks, each prefixed with its size in hexadecimal followed by CRLF (\r\n). The error typically indicates that the server sending the response is not correctly implementing the HTTP/1.1 chunked encoding specification (RFC 7230). This can happen when chunk size headers are malformed, missing required line endings, or when the response stream is corrupted during transmission. Node.js has become increasingly strict about HTTP specification compliance, and responses that were previously tolerated may now trigger this error in newer Node.js versions.
Enable detailed HTTP debugging to see the exact malformed response:
# Set NODE_DEBUG environment variable
NODE_DEBUG=http node your-app.jsOr add logging in your Node.js code:
const http = require('http');
// Log raw response data
const req = http.request(options, (res) => {
console.log('Status:', res.statusCode);
console.log('Headers:', res.headers);
res.on('data', (chunk) => {
console.log('Chunk received:', chunk.length, 'bytes');
});
res.on('end', () => {
console.log('Response complete');
});
});
req.on('error', (err) => {
console.error('Request error:', err.message);
console.error('Error code:', err.code);
});
req.end();This will help identify whether the issue is with chunk formatting or headers.
The most common cause is when both Content-Length and Transfer-Encoding: chunked are present. Inspect the response headers:
const http = require('http');
http.get('http://problematic-server.com/api', (res) => {
const contentLength = res.headers['content-length'];
const transferEncoding = res.headers['transfer-encoding'];
if (contentLength && transferEncoding === 'chunked') {
console.error('ERROR: Both Content-Length and Transfer-Encoding present!');
console.error('Content-Length:', contentLength);
console.error('This violates HTTP spec and causes parsing errors');
}
});If both headers are present, the issue is on the server side and needs to be fixed there. The Content-Length header must be removed when using chunked encoding.
Verify whether the problem is Node.js-specific or a genuine server issue:
# Test with curl to see raw response
curl -v http://your-api.com/endpoint
# Check for Transfer-Encoding header
curl -I http://your-api.com/endpoint | grep -i transfer-encodingOr test with a simple HTTP request in Python:
import requests
response = requests.get('http://your-api.com/endpoint')
print(response.headers)
print(response.status_code)If other clients work fine, the server may be sending responses that technically violate specs but are handled leniently by other parsers.
Ensure you're running a recent version of Node.js with the latest HTTP parser fixes:
# Check current Node.js version
node --version
# Update Node.js (using nvm)
nvm install --lts
nvm use --lts
# Update dependencies that might handle chunked encoding
npm update axios node-fetch got undiciSome older Node.js versions had bugs in chunked encoding handling that were fixed in later releases.
If you have control over the server sending the response, fix the chunked encoding implementation:
Remove conflicting headers:
// Express.js example
app.get('/api/data', (req, res) => {
// Don't set Content-Length when using chunked encoding
res.removeHeader('Content-Length');
// Explicitly set Transfer-Encoding if needed
res.setHeader('Transfer-Encoding', 'chunked');
res.write('chunk1');
res.write('chunk2');
res.end();
});Or disable chunked encoding entirely:
// Send complete response with Content-Length
app.get('/api/data', (req, res) => {
const data = JSON.stringify({ result: 'data' });
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Length', Buffer.byteLength(data));
res.end(data);
});Ensure your server properly implements the chunked encoding format: size in hex, \r\n, chunk data, \r\n, and terminate with 0\r\n\r\n.
If requests pass through proxies or load balancers, they may corrupt chunked encoding:
# Test direct connection vs proxied
curl -v http://server-ip:port/endpoint # Direct
curl -v http://load-balancer.com/endpoint # Through proxyCommon proxy issues:
- Nginx may modify Transfer-Encoding if not configured properly
- AWS ALB/ELB can interfere with chunked responses
- Corporate proxies may buffer and rewrite responses
Nginx configuration to preserve chunked encoding:
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_buffering off; # Important for chunked encoding
chunked_transfer_encoding on;
}If you cannot fix the server and need to work with non-compliant responses, consider using a client with more lenient parsing:
// Option 1: Use undici with lenient mode (Node.js 18+)
const { request } = require('undici');
const { statusCode, headers, body } = await request('http://api.com/endpoint', {
strictContentLength: false // More lenient with Content-Length
});
// Option 2: Use axios with custom adapter
const axios = require('axios');
const http = require('http');
const instance = axios.create({
httpAgent: new http.Agent({
// Customize agent if needed
})
});Warning: This is a workaround, not a fix. The proper solution is to correct the server's chunked encoding implementation to comply with HTTP specifications.
HTTP Chunked Encoding Format
According to RFC 7230, chunked encoding format is:
chunk-size [ chunk-ext ] CRLF
chunk-data CRLF
...
0 CRLF
[ trailer-part ] CRLFWhere chunk-size is hexadecimal (e.g., "1A" for 26 bytes) and CRLF is \r\n.
Node.js HTTP Parser Evolution
Node.js switched from the original http-parser to llhttp in Node 12, which is stricter about HTTP specification compliance. Responses that worked with older Node versions may fail with newer ones. The error codes from llhttp include:
- HPE_INVALID_CHUNK_SIZE
- HPE_UNEXPECTED_CONTENT_LENGTH
- HPE_INVALID_TRANSFER_ENCODING
Security Implications
Malformed Transfer-Encoding headers can lead to HTTP Request Smuggling vulnerabilities. Node.js has fixed several CVEs related to multi-line Transfer-Encoding headers (e.g., CVE-2021-22959). Always keep Node.js updated to protect against these vulnerabilities.
Content-Length vs Transfer-Encoding
The HTTP specification states that when both headers are present, Content-Length MUST be ignored. However, this creates ambiguity and security risks, so Node.js rejects such responses entirely. Servers must choose one encoding method or the other, never both.
Debugging Tools
Use tools like Wireshark or tcpdump to inspect raw TCP packets and see exactly what bytes the server is sending:
tcpdump -i any -s 0 -A 'tcp port 80 and host api.example.com'This can reveal invisible characters, incorrect line endings (LF vs CRLF), or other formatting issues that cause parsing errors.
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams