{"record":{"id":"61ed5e63b621ce23","repo":"denoland/deno","slug":"err-http2-invalid-packed-settings-length","errorCode":"ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH","errorMessage":"Packed settings length must be a multiple of six","messagePattern":"Packed settings length must be a multiple of six","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/http2.ts","lineNumber":5534,"sourceCode":"]);\n\nfunction getUnpackedSettings(buf) {\n  if (\n    // deno-lint-ignore deno-internal/prefer-primordials\n    !Buffer.isBuffer(buf) &&\n    !(ArrayBufferIsView(buf) && !(buf instanceof DataView))\n  ) {\n    throw new ERR_INVALID_ARG_TYPE(\"buf\", [\n      \"Buffer\",\n      \"TypedArray\",\n    ], buf);\n  }\n  if (!Buffer.isBuffer(buf)) {\n    // deno-lint-ignore deno-internal/prefer-primordials\n    buf = Buffer.from(buf);\n  }\n  if (buf.length % 6 !== 0) {\n    throw new ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH();\n  }\n\n  const settings = { __proto__: null };\n  for (let i = 0; i < buf.length; i += 6) {\n    const id = buf.readUInt16BE(i);\n    const value = buf.readUInt32BE(i + 2);\n    const name = SETTING_ID_TO_NAME.get(id);\n    if (name !== undefined) {\n      if (name === \"enablePush\" || name === \"enableConnectProtocol\") {\n        settings[name] = value !== 0;\n      } else {\n        settings[name] = value;\n        if (name === \"maxHeaderListSize\") {\n          settings.maxHeaderSize = value;\n        }\n      }\n    } else {\n      // Unknown setting IDs become custom settings","sourceCodeStart":5516,"sourceCodeEnd":5552,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/http2.ts#L5516-L5552","documentation":"The packed SETTINGS format is a sequence of 6-byte records: a 2-byte big-endian setting ID followed by a 4-byte big-endian value. getUnpackedSettings(buf) throws ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH when buf.length % 6 !== 0 because partial records cannot be decoded. The check runs after type validation, once non-Buffer inputs have been converted via Buffer.from.","triggerScenarios":"http2.getUnpackedSettings(buf) with a truncated or over-long SETTINGS payload — any byte length not divisible by 6 (e.g. 7, 11, 17); slicing a SETTINGS frame with wrong offsets, such as including the 9-byte frame header or stopping before the payload ends; concatenating unrelated bytes before decoding.","commonSituations":"Manual HTTP/2 frame parsing that miscomputes payload boundaries; hand-written test fixtures with arbitrary byte counts; reading a SETTINGS frame but slicing from the start of the frame header instead of the payload.","solutions":["Slice the exact payload: for an HTTP/2 frame, the packed settings are frame.subarray(9, 9 + frameLength) — the 9-byte header (3-byte length, type, flags, 4-byte stream id) is not part of the settings.","Guard with if (buf.length % 6 !== 0) and drop or log the malformed frame instead of decoding it.","Generate fixtures with http2.getPackedSettings(settings) — its output is always a multiple of 6 and round-trips through getUnpackedSettings."],"exampleFix":"// before\nconst settings = http2.getUnpackedSettings(frame); // frame includes 9-byte header -> length % 6 !== 0\n\n// after\nconst payloadLength = frame.readUIntBE(0, 3); // 24-bit frame length\nconst payload = frame.subarray(9, 9 + payloadLength);\nconst settings = http2.getUnpackedSettings(payload);","handlingStrategy":"validation","validationCode":"function isValidPackedSettings(buf) {\n  return (Buffer.isBuffer(buf) || ArrayBuffer.isView(buf)) && buf.length % 6 === 0;\n}\nif (!isValidPackedSettings(payload)) throw new Error('malformed SETTINGS payload');\nconst settings = http2.getUnpackedSettings(payload);","typeGuard":null,"tryCatchPattern":"try {\n  const s = http2.getUnpackedSettings(buf);\n} catch (e) {\n  if (e.code === 'ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH') {\n    // drop/log the malformed frame, do not decode\n  } else throw e;\n}","preventionTips":["Never decode a SETTINGS frame including its 9-byte header; packed settings are the payload only.","Round-trip fixtures through http2.getPackedSettings to guarantee well-formed input.","Validate length % 6 === 0 before decoding untrusted wire data."],"tags":["http2","settings","protocol-parsing","buffer","validation"],"backgroundTag":"http2-protocol-malformed-frame","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}