denoland/deno · error · Error
ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS
ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS
Error message
Number of custom settings exceeds MAX_ADDITIONAL_SETTINGS
What it means
The customSettings map in HTTP/2 settings (http2.connect(url, { settings }), http2.createServer({ settings }), session.updateSettings) carries non-standard SETTINGS identifiers. validateSettings counts ObjectEntries(settings.customSettings) and throws ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS when there are more than MAX_ADDITIONAL_SETTINGS, which is 10 (ext/node/polyfills/internal/http2/util.ts:217). The transport layer only reserves room for ten extra entries.
Source
Thrown at ext/node/polyfills/http2.ts:1370
// 1. headerTableSize must be a number in the range 0 <= n <= kMaxInt
// 2. initialWindowSize must be a number in the range 0 <= n <= kMaxInitWindowSize
// 3. maxFrameSize must be a number in the range 16384 <= n <= kMaxFrameSize
// 4. maxConcurrentStreams must be a number in the range 0 <= n <= kMaxStreams
// 5. maxHeaderListSize must be a number in the range 0 <= n <= kMaxInt
// 6. enablePush must be a boolean
// 7. enableConnectProtocol must be a boolean
// All settings are optional and may be left undefined
const validateSettings = hideStackFrames((settings) => {
if (settings === undefined) return;
assertIsObject(
settings.customSettings,
"customSettings",
"Number",
);
if (settings.customSettings) {
const entries = ObjectEntries(settings.customSettings);
if (entries.length > MAX_ADDITIONAL_SETTINGS) {
throw new ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS();
}
for (const { 0: key, 1: value } of new SafeArrayIterator(entries)) {
assertWithinRange(
"customSettings:id",
Number(key),
0,
0xffff,
);
assertWithinRange(
"customSettings:value",
Number(value),
0,
kMaxInt,
);
}
}
assertWithinRange(View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Trim customSettings to at most 10 entries and keep only the ids you actually need
- Use the standard named settings (headerTableSize, initialWindowSize, maxFrameSize, etc.) where possible instead of custom ids
- Remember ids must be integers in 0..0xffff and values in 0..0xffffffff, which are validated right after this check
Example fix
// before
const customSettings = Object.fromEntries(
Array.from({ length: 16 }, (_, i) => [0x100 + i, 1]),
);
http2.connect(url, { settings: { customSettings } }); // throws
// after
const customSettings = { 0x100: 1, 0x101: 2 }; // at most 10 entries
http2.connect(url, { settings: { customSettings } }); Defensive patterns
Strategy: validation
Validate before calling
const MAX_CUSTOM_SETTINGS = 10;
const entries = Object.entries(settings.customSettings ?? {});
if (entries.length > MAX_CUSTOM_SETTINGS) {
throw new RangeError(`customSettings exceeds ${MAX_CUSTOM_SETTINGS} entries`);
}
http2.connect(url, { settings }); Type guard
const isBoundedCustomSettings = (
v: unknown,
): v is Record<number, number> => {
if (v == null) return true;
const entries = Object.entries(v as object);
return entries.length <= 10 && entries.every(
([k, val]) =>
Number(k) >= 0 && Number(k) <= 0xffff &&
Number(val) >= 0 && Number(val) <= 0xffffffff,
);
}; Prevention
- Keep customSettings to the handful of ids you actually negotiated with the peer
- Validate settings objects at config-load time, not at connect time
- Remember ids are 0..0xffff and values 0..0xffffffff
When it happens
Trigger: Passing a customSettings object with 11 or more keys to http2.connect or http2.createServer; generating customSettings programmatically from a table of experimental settings ids; merging multiple config sources until the map exceeds ten entries.
Common situations: Protocol-experimentation code that enumerates many unknown SETTINGS ids; config merging that accumulates custom settings across environments; copying another peer's full settings dump (which may include many custom ids) into your client config.
Related errors
- ERR_HTTP2_INVALID_SETTING_VALUE
- ERR_HTTP2_PUSH_DISABLED
- ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS
- ERR_INVALID_URL
- ERR_HTTP2_NO_SOCKET_MANIPULATION
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/f07d78288085c4f9.
Report an issue: GitHub.