{"record":{"id":"f07d78288085c4f9","repo":"denoland/deno","slug":"err-http2-too-many-custom-settings","errorCode":"ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS","errorMessage":"Number of custom settings exceeds MAX_ADDITIONAL_SETTINGS","messagePattern":"Number of custom settings exceeds MAX_ADDITIONAL_SETTINGS","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/http2.ts","lineNumber":1370,"sourceCode":"// 1. headerTableSize must be a number in the range 0 <= n <= kMaxInt\n// 2. initialWindowSize must be a number in the range 0 <= n <= kMaxInitWindowSize\n// 3. maxFrameSize must be a number in the range 16384 <= n <= kMaxFrameSize\n// 4. maxConcurrentStreams must be a number in the range 0 <= n <= kMaxStreams\n// 5. maxHeaderListSize must be a number in the range 0 <= n <= kMaxInt\n// 6. enablePush must be a boolean\n// 7. enableConnectProtocol must be a boolean\n// All settings are optional and may be left undefined\nconst validateSettings = hideStackFrames((settings) => {\n  if (settings === undefined) return;\n  assertIsObject(\n    settings.customSettings,\n    \"customSettings\",\n    \"Number\",\n  );\n  if (settings.customSettings) {\n    const entries = ObjectEntries(settings.customSettings);\n    if (entries.length > MAX_ADDITIONAL_SETTINGS) {\n      throw new ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS();\n    }\n    for (const { 0: key, 1: value } of new SafeArrayIterator(entries)) {\n      assertWithinRange(\n        \"customSettings:id\",\n        Number(key),\n        0,\n        0xffff,\n      );\n      assertWithinRange(\n        \"customSettings:value\",\n        Number(value),\n        0,\n        kMaxInt,\n      );\n    }\n  }\n\n  assertWithinRange(","sourceCodeStart":1352,"sourceCodeEnd":1388,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/http2.ts#L1352-L1388","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst customSettings = Object.fromEntries(\n  Array.from({ length: 16 }, (_, i) => [0x100 + i, 1]),\n);\nhttp2.connect(url, { settings: { customSettings } }); // throws\n\n// after\nconst customSettings = { 0x100: 1, 0x101: 2 }; // at most 10 entries\nhttp2.connect(url, { settings: { customSettings } });","handlingStrategy":"validation","validationCode":"const MAX_CUSTOM_SETTINGS = 10;\nconst entries = Object.entries(settings.customSettings ?? {});\nif (entries.length > MAX_CUSTOM_SETTINGS) {\n  throw new RangeError(`customSettings exceeds ${MAX_CUSTOM_SETTINGS} entries`);\n}\nhttp2.connect(url, { settings });","typeGuard":"const isBoundedCustomSettings = (\n  v: unknown,\n): v is Record<number, number> => {\n  if (v == null) return true;\n  const entries = Object.entries(v as object);\n  return entries.length <= 10 && entries.every(\n    ([k, val]) =>\n      Number(k) >= 0 && Number(k) <= 0xffff &&\n      Number(val) >= 0 && Number(val) <= 0xffffffff,\n  );\n};","tryCatchPattern":null,"preventionTips":["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"],"tags":["http2","settings","limits","node-compat"],"backgroundTag":"http2-settings-limit","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}