decolua/9router · error

AWS EventStream message CRC mismatch

Error message

AWS EventStream message CRC mismatch

What it means

Every EventStream frame ends with a CRC32 of the entire message (all bytes except the trailing CRC itself). parseEventFrame() computes crc32(data.subarray(0, totalLength - 4)) and compares it to the last 4 bytes; mismatch means the frame's payload/headers were corrupted after the prelude CRC passed. This is the final integrity gate before headers and JSON payload are decoded.

Source

Thrown at open-sse/executors/kiro.js:1215

  if (!(data instanceof Uint8Array) || data.byteLength < 16) {
    throw new Error("AWS EventStream frame is shorter than 16 bytes");
  }
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
  const totalLength = view.getUint32(0, false);
  const headersLength = view.getUint32(4, false);
  if (totalLength !== data.byteLength) {
    throw new Error("AWS EventStream frame length does not match its prelude");
  }
  if (totalLength > EVENTSTREAM_MAX_MESSAGE_BYTES ||
      headersLength > EVENTSTREAM_MAX_HEADERS_BYTES ||
      headersLength > totalLength - 16) {
    throw new Error("AWS EventStream frame bounds are invalid");
  }
  if (view.getUint32(8, false) !== crc32(data.subarray(0, 8))) {
    throw new Error("AWS EventStream prelude CRC mismatch");
  }
  if (view.getUint32(totalLength - 4, false) !== crc32(data.subarray(0, totalLength - 4))) {
    throw new Error("AWS EventStream message CRC mismatch");
  }

  const headers = Object.create(null);
  const names = new Set();
  let offset = 12;
  const headerEnd = offset + headersLength;
  const requireBytes = (count) => {
    if (offset + count > headerEnd) {
      throw new Error("AWS EventStream header exceeds its declared bounds");
    }
  };

  while (offset < headerEnd) {
    requireBytes(1);
    const nameLength = data[offset++];
    requireBytes(nameLength + 1);
    const name = decoder.decode(data.subarray(offset, offset + nameLength));
    offset += nameLength;

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Copy each complete frame out of the read buffer (slice, not subarray) before parsing so later reads cannot mutate it.
  2. Retry the request — corruption is usually transient transport damage.
  3. Bypass transforming proxies (compression/rewriting layers) for the Kiro EventStream endpoint.
  4. Drop and resynchronize the stream after a bad frame instead of continuing (the executor already cancels the reader on invalid frames — keep that behavior).
  5. Update Node/undici/9router if the corruption reproduces on every request (possible SDK streaming bug).

Example fix

// before: parse deferred while buffer stays shared with the reader
pendingFrames.push(chunk.subarray(start, end));
// ...later, after more reads...
parseEventFrame(pendingFrames[0]); // bytes may already be overwritten

// after: parse or copy immediately
const frame = chunk.slice(start, end);
parseEventFrame(frame);
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const { headers, payload } = parseEventFrame(frame);
  handleFrame(headers, payload);
} catch (e) {
  if (e.message.includes('message CRC mismatch')) {
    log.warn('kiro: frame payload corrupted, aborting stream');
    await reader.cancel('invalid Kiro EventStream');
    await retryWithBackoff();
  } else throw e;
}

Prevention

When it happens

Trigger: The recomputed message CRC differs from view.getUint32(totalLength - 4, false): bytes between offset 12 and totalLength-4 were modified in transit, the buffer contents changed between read and parse (reused underlying ArrayBuffer), or the parser is reading a frame assembled from mis-joined chunks.

Common situations: Flaky upstream connection or corrupted intermediate hop; a shared/aliased buffer overwritten by a subsequent reader.read() before parsing; a proxy re-encoding (e.g. gzipping) the binary body; desynced multi-frame parsing where chunk boundaries were stitched incorrectly.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/0cc4f862008a50b7. Report an issue: GitHub.