{"record":{"id":"af1d6907488a1845","repo":"denoland/deno","slug":"err-http2-ping-length","errorCode":"ERR_HTTP2_PING_LENGTH","errorMessage":"HTTP2 ping payload must be 8 bytes","messagePattern":"HTTP2 ping payload must be 8 bytes","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/http2.ts","lineNumber":4197,"sourceCode":"  // been called, the ping callback will be invoked immediately with a ping\n  // cancelled error and a duration of 0.0.\n  ping(payload, callback) {\n    if (this.destroyed) {\n      throw new ERR_HTTP2_INVALID_SESSION();\n    }\n\n    if (typeof payload === \"function\") {\n      callback = payload;\n      payload = undefined;\n    }\n    if (payload) {\n      validateBuffer(payload, \"payload\");\n    }\n    // Use byteLength rather than length so non-Uint8Array views (e.g. a\n    // Uint16Array of 4 elements = 8 bytes) are correctly accepted, matching\n    // Node's Http2Session#ping which validates the underlying byte length.\n    if (payload && payload.byteLength !== 8) {\n      throw new ERR_HTTP2_PING_LENGTH();\n    }\n    validateFunction(callback, \"callback\");\n\n    // Allocate an HTTP2PING async resource so async_hooks observers see\n    // init/before/after/destroy for each ping, matching Node's Http2Ping\n    // AsyncWrap in src/node_http2.cc.\n    const userCb = pingCallback(callback);\n    const asyncResource = new AsyncResource(\"HTTP2PING\");\n    const cb = (ack, duration, ackPayload) => {\n      try {\n        asyncResource.runInAsyncScope(\n          userCb,\n          this,\n          ack,\n          duration,\n          ackPayload,\n        );\n      } finally {","sourceCodeStart":4179,"sourceCodeEnd":4215,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/http2.ts#L4179-L4215","documentation":"HTTP/2 PING frames carry exactly 8 bytes of opaque payload, so session.ping(payload, cb) throws ERR_HTTP2_PING_LENGTH when payload.byteLength !== 8. The check deliberately uses byteLength, not length, so a Uint16Array view with 4 elements (8 bytes) is accepted while a 9-byte Buffer is not, matching Node's native validation.","triggerScenarios":"session.ping(Buffer.from('123456789')) (9 bytes), ping(Buffer.alloc(0)), ping(new Uint8Array(16)), or any TypedArray/Buffer whose underlying byte length is not exactly 8.","commonSituations":"Using a hex-encoded timestamp string (16 characters = 16 bytes) as the payload; generating 'random' IDs with randomBytes(16) copy-pasted from UUID code; sending an application heartbeat object serialized to JSON of arbitrary length.","solutions":["Omit the payload entirely and just call session.ping(callback) — Node fills zeros","Use crypto.randomBytes(8) or Buffer.alloc(8) for a well-formed payload","Pre-check payload && payload.byteLength !== 8 and fix or reject before calling"],"exampleFix":"// before\nsession.ping(Buffer.from(JSON.stringify({ t: Date.now() })), cb);\n\n// after\nsession.ping(cb); // or: session.ping(crypto.randomBytes(8), cb);","handlingStrategy":"validation","validationCode":"const payload = makePayload(); // user data\nif (payload !== undefined && payload.byteLength !== 8) {\n  throw new RangeError(`ping payload must be 8 bytes, got ${payload.byteLength}`);\n}\nsession.ping(payload, callback);","typeGuard":"function isValidPingPayload(p) {\n  return p === undefined || (ArrayBuffer.isView(p) && p.byteLength === 8);\n}","tryCatchPattern":null,"preventionTips":["Use crypto.randomBytes(8) or Buffer.alloc(8) — never arbitrary-length serialized data","Remember the check is byteLength: a Uint16Array(4) view is 8 bytes and valid","Omitting the payload is always safe"],"tags":["http2","node-compat","ping","argument-validation"],"backgroundTag":"argument-validation-failed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}