How to fix Error: HTTP/2 FRAME_SIZE_ERROR (frame payload exceeds limit) in Node.js

Node.jsINTERMEDIATEMEDIUMUpdated Dec 9, 2025ยท 126 views

This error occurs when an HTTP/2 frame payload exceeds the maximum allowed frame size limit. HTTP/2 enforces strict frame size constraints (default 16KB), and this error indicates the server or client sent a frame that violates these limits, preventing the connection from continuing.

Quick fix

Fixes FRAME_SIZE_ERROR

const http2 = require('http2');

// Server advertising its settings
const server = http2.createSecureServer({
  // Maximum frame size this server will accept
  settings: {
    maxFrameSize: 16384  // Default: 16KB
  }
});

// Client setting its own maximum frame size
const client = http2.connect('https://api.example.com', {
  settings: {
    maxFrameSize: 16384
  }
});
  1. Understand HTTP/2 frame size defaults
  2. Increase the maximum frame size on server
  3. Increase client-side maximum frame size
  4. Reduce request/response size instead
node.js โ€” error
const http2 = require('http2');
// Server advertising its settings
const server = http2.createSecureServer({
// Maximum frame size this server will accept
settings: {
maxFrameSize: 16384 // Default: 16KB
}
});
// Client setting its own maximum frame size
const client = http2.connect('https://api.example.com', {
settings: {
maxFrameSize: 16384
}
});
Error: HTTP/2 FRAME_SIZE_ERROR (frame payload exceeds limit)

What this error means

The "HTTP/2 FRAME_SIZE_ERROR" in Node.js indicates that a frame in the HTTP/2 stream has a payload that exceeds the negotiated maximum frame size. HTTP/2 is a binary framing protocol where data is sent in discrete frames with strict size limitations. When either the server or client sends a frame larger than the maximum frame size setting (default 16,384 bytes), the HTTP/2 protocol layer rejects it with a FRAME_SIZE_ERROR. This is a protocol-level violation that causes the connection to be terminated. The error typically appears during: - Large file uploads or downloads - Sending large request/response headers - Streaming data with custom frame sizes - Misconfigured HTTP/2 settings that aren't aligned between client and server - Third-party proxy or load balancer interference with HTTP/2 frames Unlike HTTP/1.1 chunked encoding that allows large payloads, HTTP/2 frames have explicit size limits that must be respected.

Typical symptoms

  • HTTP/2 connection terminates with FRAME_SIZE_ERROR
  • Large file uploads fail before sending
  • Streaming responses break unexpectedly
  • Error appears in h2 or http2 module error handlers
  • Works with HTTP/1.1 but fails with HTTP/2
  • Same request succeeds to different servers
  • Headers or body size changes trigger the error
  • Connection resets without timeout error

Common causes

  1. Request or response payload exceeds the max frame size setting (default 16KB)
  2. Custom maxFrameSize setting conflicts between client and server
  3. Large cookie headers exceed frame size limits
  4. Proxy or load balancer strips HTTP/2 frame size negotiations
  5. Sending uncompressed headers that exceed frame size after HTTP/2 compression
  6. Custom middleware or middleware adds large headers to requests
  7. Streaming response sends more data than advertised content length
  8. HTTP/2 server settings not properly communicated to client

How to fix "Error: HTTP/2 FRAME_SIZE_ERROR (frame payload exceeds limit)"

1Understand HTTP/2 frame size defaults

HTTP/2 frames have size limits set during the SETTINGS frame exchange. The default maximum frame size is 16,384 bytes (16KB).

Both client and server negotiate frame sizes:

javascript
const http2 = require('http2');

// Server advertising its settings
const server = http2.createSecureServer({
  // Maximum frame size this server will accept
  settings: {
    maxFrameSize: 16384  // Default: 16KB
  }
});

// Client setting its own maximum frame size
const client = http2.connect('https://api.example.com', {
  settings: {
    maxFrameSize: 16384
  }
});

If either side sends a frame larger than the negotiated size, the connection fails with FRAME_SIZE_ERROR.

2Increase the maximum frame size on server

If you control the server, increase the maxFrameSize setting to accommodate larger payloads:

javascript
const http2 = require('http2');
const fs = require('fs');

const options = {
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
  settings: {
    headerTableSize: 65536,
    enablePush: true,
    initialWindowSize: 65535,
    maxFrameSize: 1048576,  // Increase to 1MB (be careful with memory!)
    maxConcurrentStreams: 100,
    maxHeaderListSize: 8192
  }
};

const server = http2.createSecureServer(options, (req, res) => {
  res.writeHead(200, { 'content-type': 'application/json' });
  res.end(JSON.stringify({ message: 'Hello from HTTP/2' }));
});

server.listen(443, () => {
  console.log('HTTP/2 server listening on https://localhost:443');
});

Important: Increasing frame size uses more memory. Start conservatively (32KB or 64KB) and monitor resource usage.

3Increase client-side maximum frame size

If making HTTP/2 requests to a server you don't control, increase your client's max frame size:

javascript
const http2 = require('http2');

const client = http2.connect('https://api.example.com', {
  settings: {
    maxFrameSize: 1048576  // Increase to 1MB
  }
});

const req = client.request({
  ':path': '/large-file',
  ':method': 'GET'
});

req.on('response', (headers) => {
  console.log('Status:', headers[':status']);
});

req.on('data', (chunk) => {
  console.log('Received chunk:', chunk.length, 'bytes');
});

req.on('end', () => {
  client.close();
});

req.on('error', (err) => {
  if (err.code === 'FRAME_SIZE_ERROR') {
    console.error('Frame size exceeded. Server may not support large frames.');
  }
  client.close();
});

Or with the request/client library:

javascript
const https = require('https');
const Agent = require('agentkeepalive').HttpsAgent;

const agentOptions = {
  maxFrameSize: 1048576
};

const options = {
  hostname: 'api.example.com',
  path: '/large-file',
  agent: new Agent(agentOptions)
};

https.get(options, (res) => {
  // Handle response
});
4Reduce request/response size instead

Instead of increasing frame size, reduce the data sent in individual frames:

For request payloads:

javascript
const http2 = require('http2');
const fs = require('fs');

const client = http2.connect('https://api.example.com');

// Stream large file in chunks rather than all at once
const fileStream = fs.createReadStream('large-file.bin', {
  highWaterMark: 16384  // Read in 16KB chunks
});

const req = client.request({
  ':method': 'POST',
  ':path': '/upload'
});

fileStream.pipe(req);

req.on('response', (headers) => {
  console.log('Upload status:', headers[':status']);
});

For response payloads:

javascript
const http2 = require('http2');
const zlib = require('zlib');

const server = http2.createSecureServer(options, (req, res) => {
  // Compress response headers to reduce frame size
  const gzip = zlib.createGzip();

  res.writeHead(200, {
    'content-type': 'application/json',
    'content-encoding': 'gzip'
  });

  // Stream data in smaller chunks
  process.stdout.pipe(gzip).pipe(res);
});
5Check for large headers

Large headers (especially cookies) can exceed frame size. Compress and minimize headers:

javascript
const http2 = require('http2');

const client = http2.connect('https://api.example.com', {
  settings: {
    maxHeaderListSize: 8192  // Limit header list size
  }
});

// Check header sizes before sending
function checkHeaderSize(headers) {
  let totalSize = 0;
  for (const [key, value] of Object.entries(headers)) {
    totalSize += key.length + value.toString().length;
  }
  console.log('Header size:', totalSize, 'bytes');

  if (totalSize > 16384) {
    console.warn('Headers may exceed frame size!');
  }

  return totalSize;
}

const headers = {
  ':path': '/api/data',
  ':method': 'GET',
  'cookie': 'sessionid=...',  // Minimize cookies
  'user-agent': 'MyApp/1.0'
};

checkHeaderSize(headers);

const req = client.request(headers);

Tips:
- Remove unnecessary cookies
- Compress large header values
- Use HTTP/2 header compression (built-in with HPACK)
- Split cookies across multiple requests if needed

6Debug with HTTP/2 session errors

Add error handlers to catch FRAME_SIZE_ERROR early:

javascript
const http2 = require('http2');

const client = http2.connect('https://api.example.com');

// Listen for session errors
client.on('error', (err) => {
  console.error('Session error:', err.code, err.message);

  if (err.code === 'FRAME_SIZE_ERROR') {
    console.error('Action: Increase maxFrameSize on client or server');
  }
});

// Listen for stream errors
const req = client.request({
  ':path': '/large-file',
  ':method': 'GET'
});

req.on('error', (err) => {
  console.error('Stream error:', err.code, err.message);
});

// Get current settings
client.on('remoteSettings', (settings) => {
  console.log('Remote max frame size:', settings.maxFrameSize);
  console.log('Remote max header list size:', settings.maxHeaderListSize);
});

client.on('localSettings', (settings) => {
  console.log('Local max frame size:', settings.maxFrameSize);
});
7Check if proxy/load balancer is stripping HTTP/2 settings

Some proxies don't properly handle HTTP/2 frame size negotiations. Test direct connection:

bash
# Test direct connection to origin server
curl --http2 https://api.example.com:8443/large-file --output test.bin

# Test through proxy
curl --http2 --proxy https://proxy.example.com:3128 https://api.example.com/large-file --output test.bin

# Compare sizes and check for errors

If it works direct but fails through proxy:

1. Check proxy HTTP/2 configuration
2. Verify proxy supports HTTP/2 frame size forwarding
3. Consider bypassing proxy for large transfers
4. Contact proxy administrator about HTTP/2 compliance

javascript
const http2 = require('http2');

// Some proxies may require specific settings
const client = http2.connect('https://api.example.com', {
  settings: {
    maxFrameSize: 16384,  // Use default to avoid proxy issues
    maxHeaderListSize: 8192
  },
  // Disable push if proxy has issues
  settings: { enablePush: false }
});

Advanced notes

HTTP/2 Frame Size Negotiation

HTTP/2 uses a SETTINGS frame to negotiate frame sizes. The negotiation happens during connection setup:

1. Server sends initial SETTINGS frame with its max frame size
2. Client receives and acknowledges with SETTINGS ACK
3. Client sends its SETTINGS frame
4. Server acknowledges with SETTINGS ACK
5. Both sides use the more conservative limit

The default maximum is 16,384 bytes (16KB). The maximum possible value is 16,777,215 bytes (~16MB), but increasing it consumes more memory.

Memory Implications

Each HTTP/2 connection maintains a buffer for incoming frames. A larger maxFrameSize means:
- More memory per connection
- Larger temporary buffers
- Higher peak memory usage during transfers

For a server with 1000 concurrent connections:
- At 16KB: ~16MB base
- At 1MB: ~1GB base
- At 16MB: ~16GB base

Scale accordingly for your infrastructure.

Common Causes by Scenario

Large File Upload: Client is sending a file in a single frame. Solution: stream the data or increase server's maxFrameSize.

Large Response Headers: Server sends HTTP response with many or large headers in a single HEADERS frame. Solution: compress headers or increase client's maxHeaderListSize.

Streaming with Custom Frames: Middleware or custom streaming logic sends frames larger than negotiated size. Solution: check middleware configuration or implement proper frame chunking.

Proxy Interference: Some proxies terminate HTTP/2 and re-establish connections without properly forwarding settings. Solution: test direct connection or update proxy configuration.

HPACK Header Compression

HTTP/2 uses HPACK compression for headers. This reduces header size significantly. If headers still exceed limits after compression, the frame is too large. Check the post-compression size:

javascript
// The actual frame size includes HPACK-compressed headers
// Original headers might be 1MB, but compress to 10KB
const headers = {
  ':path': '/api/endpoint',
  'authorization': 'Bearer token...',
  'content-type': 'application/json'
  // Many more headers...
};

// HTTP/2 compresses these using HPACK before sending
// If compressed size > maxFrameSize, error occurs

Testing Frame Sizes

Use h2load tool to test frame sizes:

bash
# Test with specific frame size
h2load --max-concurrent-streams=1 --rate=1 \
  -H "custom-header: very-long-value-repeated-many-times..." \
  https://api.example.com/test

Frequently asked questions

What does "FRAME_SIZE_ERROR" mean?
js indicates that a frame in the HTTP/2 stream has a payload that exceeds the negotiated maximum frame size. HTTP/2 is a binary framing protocol where data is sent in discrete frames with strict size limitations. When either the server or client sends a frame larger than the maximum frame size setting (default 16,384 bytes), the HTTP/2 protocol layer rejects it with a FRAME_SIZE_ERROR.
How do I fix "FRAME_SIZE_ERROR"?
This error occurs when an HTTP/2 frame payload exceeds the maximum allowed frame size limit. HTTP/2 enforces strict frame size constraints (default 16KB), and this error indicates the server or client sent a frame that violates these limits, preventing the connection from continuing.
What causes "FRAME_SIZE_ERROR"?
Request or response payload exceeds the max frame size setting (default 16KB) Custom maxFrameSize setting conflicts between client and server Large cookie headers exceed frame size limits
Is the "FRAME_SIZE_ERROR" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading