This error occurs when a Node.js HTTP client receives an HTTP response with a version string that the parser cannot recognize or does not support. It typically indicates a protocol mismatch, malformed server response, or incompatibility with an intermediary like a proxy or load balancer.
The "Invalid HTTP version" error is raised when Node.js's HTTP parser encounters an unrecognized HTTP version string in a server response or request line. The HTTP specification defines valid versions like HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3, but servers or proxies may return malformed versions like "HTTP/2.0" (invalid), "HTTP/1" (incomplete), or corrupted version strings. Node.js validates HTTP versions strictly during parsing. When the parser encounters a version it cannot understand or that doesn't conform to the HTTP specification, it throws this error to prevent processing a potentially malicious or corrupted message. This error is distinct from protocol mismatch errors (using http:// with an HTTPS endpoint) and usually indicates either a server configuration issue, proxy misconfiguration, or data corruption during transmission. It often surfaces in proxy environments, CDN requests, or connections through middleware that may rewrite HTTP headers.
Check what HTTP version your target server supports using curl or other tools:
# Test HTTP/1.1 (default)
curl -v http://example.com
# Test HTTP/2
curl --http2 -v https://example.com
# Test HTTP/3 (QUIC)
curl --http3 -v https://example.com
# Check response headers and protocol version
curl -i http://example.com | head -20The first line of the response should show a valid HTTP version like "HTTP/1.1 200 OK" or "HTTP/2 200". If you see an invalid format, the server is misconfigured.
Verify that your Node.js code is using compatible HTTP versions:
const http = require('http');
const https = require('https');
// Standard HTTP/1.1 request (default)
const req = https.get('https://example.com', (res) => {
console.log(`Protocol: ${res.httpVersion}`); // Should be "1.1" or "2.0"
res.pipe(process.stdout);
});
req.on('error', (err) => {
console.error('Request error:', err.message);
});Ensure you're using http for HTTP URLs and https for HTTPS URLs. Mixing protocols causes parsing issues.
If the error occurs when routing through a proxy, try disabling HTTP/2:
const https = require('https');
const options = {
hostname: 'example.com',
port: 443,
path: '/',
method: 'GET',
// Disable HTTP/2 for compatibility with some proxies
http2: false,
};
const req = https.request(options, (res) => {
console.log(`Status: ${res.statusCode}`);
res.on('data', (chunk) => {
process.stdout.write(chunk);
});
});
req.on('error', (err) => {
console.error('Request error:', err.message);
});
req.end();Some older proxies don't properly handle HTTP/2, causing them to return malformed version strings.
If requests fail when routing through a proxy, review the proxy settings:
For nginx reverse proxy, ensure valid HTTP version handling:
upstream backend {
server backend-server:3000;
# Ensure proxy passes valid HTTP versions
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
# Explicitly set HTTP version
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}Check that the proxy is not rewriting or corrupting the HTTP version header.
HTTP parsing in Node.js improves with each version. Update to the latest LTS or current version:
# Check current Node.js version
node --version
# Update Node.js using nvm (recommended)
nvm install --lts
nvm use --lts
# Or update via your package manager
# macOS
brew upgrade node
# Ubuntu/Debian
sudo apt update && sudo apt upgrade nodejs
# Verify update
node --versionNewer versions have better error handling and compatibility with various proxy configurations.
Handle this error gracefully and retry with different HTTP versions:
const https = require('https');
async function fetchWithFallback(url, options = {}) {
const httpVersions = ['1.1', '1.0']; // Fallback sequence
for (const version of httpVersions) {
try {
console.log(`Attempting with HTTP/${version}...`);
const opts = {
...options,
http2: version !== '1.0' && version !== '1.1',
};
return await new Promise((resolve, reject) => {
https.get(url, opts, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve(data));
}).on('error', reject);
});
} catch (err) {
console.error(`Failed with HTTP/${version}: ${err.message}`);
if (version === httpVersions[httpVersions.length - 1]) {
throw err; // All versions failed
}
}
}
}
fetchWithFallback('https://example.com')
.then((data) => console.log('Success:', data))
.catch((err) => console.error('All attempts failed:', err.message));This approach automatically retries with different HTTP versions if the server is misconfigured.
Use network debugging tools to see the exact HTTP version being returned:
# Capture HTTP traffic with tcpdump
sudo tcpdump -i any -A 'tcp port 443 or tcp port 80' | grep -i 'HTTP'
# Or use Wireshark for GUI packet inspection
wireshark
# Use curl with maximum verbosity
curl -vvv http://example.com 2>&1 | head -40
# Check for Node.js HTTP debug logs
NODE_DEBUG=http node your-script.js 2>&1 | head -50Look for the exact response line. Valid responses should look like:
- HTTP/1.1 200 OK
- HTTP/2 200
- HTTP/1.0 200 OK
Invalid responses might show corrupted version strings like HTTP/2.0 or HTTP without a version.
Understanding HTTP Version Parsing in Node.js
Node.js uses the llhttp library (successor to http-parser) for HTTP parsing. The parser strictly validates HTTP versions against the HTTP specification. Valid versions include:
- HTTP/1.0 (deprecated but still supported)
- HTTP/1.1 (most common)
- HTTP/2 (or h2)
- HTTP/3 (QUIC, newer)
The parser rejects anything that doesn't match the pattern, including:
- HTTP/2.0 (should be HTTP/2)
- HTTP/1 (incomplete, needs .0 or .1)
- HTTPS/1.1 (HTTPS is a protocol, not a version)
- h2c (HTTP/2 Cleartext) over non-encrypted connections may also cause issues
Proxy-Specific Issues
Corporate proxies, especially older ones or those with SSL inspection, may:
- Rewrite HTTP version headers
- Return malformed upgrade responses
- Fail to properly translate between HTTP versions
- Inject custom headers that break parsing
Solutions:
1. Bypass the proxy if possible for specific requests
2. Configure the proxy to use HTTP/1.1 exclusively
3. Use a proxy authentication library if credentials are needed
4. Contact proxy administrator to update configuration
TLS/SSL Interception Problems
Some security appliances intercept HTTPS traffic and re-encrypt it, potentially corrupting HTTP version information. If the error only occurs with HTTPS:
// Allow self-signed certificates from intercepting proxy (development only)
const https = require('https');
const agent = new https.Agent({
rejectUnauthorized: false, // WARNING: For testing only!
});
https.get('https://example.com', { agent }, (res) => {
console.log('Success');
});In production, work with your security team to configure proper certificate chains.
HTTP/2 Server Push and Version Mismatches
If using HTTP/2 server push, ensure your client properly handles it:
const spdy = require('spdy'); // For HTTP/2 support
const req = spdy.request(options, (res) => {
res.on('push', (err, pushedRes) => {
if (err) {
console.error('Push error:', err.message);
return;
}
console.log('Received push:', pushedRes.url);
});
});Ensure both client and server negotiate the same protocol version in TLS handshake.
Load Balancer Configuration
For applications behind load balancers (AWS ELB, Google Load Balancer, etc.):
- AWS ALB: Ensure HTTP/2 is enabled if clients expect it
- Google Cloud Load Balancer: Check HTTP version settings
- Kubernetes Ingress: Verify ingress controller HTTP version support
Contact your hosting provider's support if upgrading HTTP versions on load balancers.
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