decolua/9router · error

AWS EventStream frame bounds are invalid

Error message

AWS EventStream frame bounds are invalid

What it means

After the prelude passes basic consistency checks, parseEventFrame() sanity-checks the declared totalLength against EVENTSTREAM_MAX_MESSAGE_BYTES, the headersLength against EVENTSTREAM_MAX_HEADERS_BYTES, and requires headersLength to fit within totalLength - 16 (prelude + CRC). This is a resource-exhaustion / malicious-payload guard: an absurd length would otherwise drive huge allocations or out-of-bounds header parsing.

Source

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

/**
 * Parse AWS EventStream frame
 */

function parseEventFrame(data) {
  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");
    }
  };

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Re-sync stream parsing: after each frame, advance exactly totalLength bytes so payload bytes are never misread as the next prelude.
  2. Retry the request — random corruption points to the transport, not the frame format.
  3. Bypass MITM/transforming proxies (or TLS-inspecting firewalls) for the Kiro endpoint.
  4. If legitimate frames exceed the caps, raise EVENTSTREAM_MAX_MESSAGE_BYTES / EVENTSTREAM_MAX_HEADERS_BYTES in open-sse config for very large tool_result payloads.
  5. Verify the Kiro base URL points at the real CodeWhisperer/Kiro EventStream endpoint, not an HTML error page.
Defensive patterns

Strategy: validation

Validate before calling

function frameBoundsOk(data, MAX_MSG, MAX_HDR) {
  if (!(data instanceof Uint8Array) || data.byteLength < 16) return false;
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
  const total = view.getUint32(0, false), hdr = view.getUint32(4, false);
  return total === data.byteLength && total <= MAX_MSG && hdr <= MAX_HDR && hdr <= total - 16;
}
if (frameBoundsOk(buf, EVENTSTREAM_MAX_MESSAGE_BYTES, EVENTSTREAM_MAX_HEADERS_BYTES)) parseEventFrame(buf);

Type guard

function hasSanePrelude(v) {
  if (!(v instanceof Uint8Array) || v.byteLength < 16) return false;
  const view = new DataView(v.buffer, v.byteOffset, v.byteLength);
  const total = view.getUint32(0, false), hdr = view.getUint32(4, false);
  return total <= 0x4000000 && hdr <= total - 16;
}

Try / catch

try {
  parseEventFrame(frame);
} catch (e) {
  if (e.message.includes('bounds are invalid')) {
    log.error('kiro: insane frame bounds, possible desync or MITM');
    cancelAndResyncStream();
  } else throw e;
}

Prevention

When it happens

Trigger: A corrupted or hostile frame declares a totalLength or headersLength beyond configured maxima, or headersLength so large it cannot fit inside the frame (headersLength > totalLength - 16) — e.g. random bytes interpreted as a prelude, or a length field flipped by transmission corruption.

Common situations: Connecting to a non-EventStream endpoint or a proxy error page whose bytes are misparsed as a prelude; a man-in-the-middle rewriting binary bodies; desynced stream parsing where a payload's bytes are consumed as a new frame header; memory-limit misconfiguration making legit huge frames exceed EVENTSTREAM_MAX_MESSAGE_BYTES.

Related errors


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