decolua/9router · error

AWS EventStream frame is shorter than 16 bytes

Error message

AWS EventStream frame is shorter than 16 bytes

What it means

The Kiro executor's parseEventFrame() decodes AWS EventStream binary frames, which always begin with a 12-byte prelude (total length, headers length, CRC) plus a 4-byte message CRC — 16 bytes minimum. This error is thrown when the buffer handed to the parser is not a Uint8Array or contains fewer than 16 bytes, meaning it cannot possibly hold a complete frame. It is a fail-fast integrity check on the upstream Kiro (CodeWhisperer) EventStream transport.

Source

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

        log,
        proxyOptions
      );

      return result;
    } catch (error) {
      log?.error?.("TOKEN", `Kiro refresh error: ${error.message}`);
      return null;
    }
  }
}

/**
 * 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");
  }

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Re-stream/accumulate bytes and only hand complete frames to parseEventFrame (ensure the caller buffers partial chunks until totalLength bytes are available).
  2. Retry the Kiro request — a truncated frame usually means the upstream connection was dropped mid-stream.
  3. Check for a proxy (HTTP_PROXY/HTTPS_PROXY or corporate MITM) corrupting binary EventStream bodies and bypass it for the Kiro endpoint.
  4. Verify the Kiro credentials/account are valid; an auth failure can produce a non-EventStream body that fragments into tiny chunks.
  5. Update 9router — upstream protocol changes may require a newer executor/translator.

Example fix

// before: parsing raw network chunks directly
for (const chunk of chunks) parseEventFrame(chunk);

// after: buffer until a full frame is available
let buf = new Uint8Array(0);
for (const chunk of chunks) {
  buf = concat(buf, chunk);
  if (buf.byteLength >= 16) {
    const totalLength = new DataView(buf.buffer).getUint32(0, false);
    if (buf.byteLength >= totalLength) {
      parseEventFrame(buf.subarray(0, totalLength));
      buf = buf.subarray(totalLength);
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

function isCompleteEventStreamFrame(data) {
  return data instanceof Uint8Array &&
    data.byteLength >= 16 &&
    new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0, false) === data.byteLength;
}
if (isCompleteEventStreamFrame(buf)) parseEventFrame(buf);

Type guard

function isFrameCandidate(v) {
  return v instanceof Uint8Array && v.byteLength >= 16;
}

Try / catch

try {
  parseEventFrame(frame);
} catch (e) {
  if (e.message.includes('shorter than 16 bytes')) {
    log.warn('kiro: truncated frame, reconnecting');
    await retryRequest();
  } else throw e;
}

Prevention

When it happens

Trigger: parseEventFrame() receives a Uint8Array with byteLength < 16, or a non-Uint8Array value, from the network chunk assembler feeding it — typically a partial/truncated frame fragment at the start or end of the HTTP/2 body stream from the Kiro upstream.

Common situations: Upstream connection cut mid-frame (proxy, network blip, idle timeout); a buffering bug where stream chunks are passed to the parser before being accumulated to full-frame boundaries; a MITM/intercepting proxy mangling the binary body; Kiro returning an error page or empty body instead of an EventStream.

Related errors


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