{"record":{"id":"0f1388a777dc1aed","repo":"decolua/9router","slug":"aws-eventstream-prelude-crc-mismatch","errorCode":null,"errorMessage":"AWS EventStream prelude CRC mismatch","messagePattern":"AWS EventStream prelude CRC mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"open-sse/executors/kiro.js","lineNumber":1212,"sourceCode":" */\n\nfunction parseEventFrame(data) {\n  if (!(data instanceof Uint8Array) || data.byteLength < 16) {\n    throw new Error(\"AWS EventStream frame is shorter than 16 bytes\");\n  }\n  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n  const totalLength = view.getUint32(0, false);\n  const headersLength = view.getUint32(4, false);\n  if (totalLength !== data.byteLength) {\n    throw new Error(\"AWS EventStream frame length does not match its prelude\");\n  }\n  if (totalLength > EVENTSTREAM_MAX_MESSAGE_BYTES ||\n      headersLength > EVENTSTREAM_MAX_HEADERS_BYTES ||\n      headersLength > totalLength - 16) {\n    throw new Error(\"AWS EventStream frame bounds are invalid\");\n  }\n  if (view.getUint32(8, false) !== crc32(data.subarray(0, 8))) {\n    throw new Error(\"AWS EventStream prelude CRC mismatch\");\n  }\n  if (view.getUint32(totalLength - 4, false) !== crc32(data.subarray(0, totalLength - 4))) {\n    throw new Error(\"AWS EventStream message CRC mismatch\");\n  }\n\n  const headers = Object.create(null);\n  const names = new Set();\n  let offset = 12;\n  const headerEnd = offset + headersLength;\n  const requireBytes = (count) => {\n    if (offset + count > headerEnd) {\n      throw new Error(\"AWS EventStream header exceeds its declared bounds\");\n    }\n  };\n\n  while (offset < headerEnd) {\n    requireBytes(1);\n    const nameLength = data[offset++];","sourceCodeStart":1194,"sourceCodeEnd":1230,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/executors/kiro.js#L1194-L1230","documentation":"EventStream frames carry a CRC32 checksum of the 8-byte prelude (total length + headers length) at offset 8. parseEventFrame() recomputes CRC32 over data[0..8] and compares it to the stored value; a mismatch proves the prelude bytes were corrupted (or the frame is not a genuine EventStream frame). Throwing here prevents parsing headers from garbage lengths.","triggerScenarios":"crc32(data.subarray(0, 8)) !== view.getUint32(8, false): the prelude bytes were altered in transit, the buffer was mutated/overwritten between reads (e.g. a shared/aliased ArrayBuffer reused by the reader), or non-EventStream bytes are being parsed as a frame.","commonSituations":"Unstable network path or flaky proxy flipping bytes; a custom fetch/undici dispatcher reusing a pooled buffer without copying before the next read; TLS interception that mangles binary content; desynced parsing where mid-payload bytes are treated as a frame start.","solutions":["Copy chunk bytes into a private buffer (Uint8Array.slice / new Uint8Array(bytes)) instead of holding references to reused stream buffers before parsing.","Retry the request — transient bit corruption on the wire is the usual cause.","Bypass any TLS-inspecting proxy/firewall for the Kiro endpoint and retry.","Re-sync the frame stream: if one frame fails CRC, rescan for the next plausible frame boundary rather than continuing from a desynced offset.","Update 9router / undici / Node — some versions had streaming bugs with binary response bodies."],"exampleFix":"// before: keeping a view into a buffer the reader reuses\nconst frame = chunk.subarray(off, off + totalLength); // may be overwritten later\nparseEventFrame(frame);\n\n// after: copy before enqueueing/parsing\nconst frame = chunk.slice(off, off + totalLength); // independent copy\nparseEventFrame(frame);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const { headers, payload } = parseEventFrame(frame);\n  handleFrame(headers, payload);\n} catch (e) {\n  if (e.message.includes('prelude CRC mismatch')) {\n    log.warn('kiro: prelude corrupted in transit, retrying request');\n    await retryWithBackoff();\n  } else throw e;\n}","preventionTips":["Copy frames out of reused/pooled read buffers (slice, not subarray) before parsing.","Route traffic for the Kiro endpoint outside TLS-intercepting proxies.","On CRC failure, retry the whole request — partial recovery within a corrupted frame is impossible.","Track CRC failure rate per account/network path; sustained failures indicate a broken hop, not bad luck."],"tags":["eventstream","binary-protocol","crc","data-corruption","kiro"],"backgroundTag":"eventstream-crc-mismatch","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}