grpc/grpc-java · error · IllegalArgumentException

Invalid frame length

Error message

Invalid frame length ${dataLength}

What it means

AltsFraming's parser reads a little-endian 4-byte frame length header and validates it: the declared data length must be at least FRAME_MESSAGE_TYPE_HEADER_SIZE and at most MAX_DATA_LENGTH. A length outside that range means the byte stream is corrupt or not an ALTS frame, so parsing fails fast with IllegalArgumentException.

Solutions

  1. Verify the peer is speaking the same ALTS framing protocol version
  2. Check the code producing/consuming the stream for byte misalignment (e.g. incorrect slice/offset of the length header)
  3. If dataLength is 0 confirm the writer always includes the message-type header, not just the payload
  4. Reset the connection — once the frame stream is desynchronized it cannot be recovered

Example fix

// writer side: before
buf.putInt(payload.length);
// after — include message type + payload in the length field
int dataLength = FRAME_MESSAGE_TYPE_HEADER_SIZE + payload.length;
buf.putInt(dataLength);
Defensive patterns

Strategy: try-catch

Validate before calling

int len = readLittleEndianInt32(header);
if (len < FRAME_MESSAGE_TYPE_HEADER_SIZE || len > MAX_DATA_LENGTH) {
  throw new IOException("corrupt ALTS frame length: " + len);
}

Type guard

null

Try / catch

try {
  parser.readBytes(input);
} catch (IllegalArgumentException e) {
  // framing desynchronized: discard the stream and reset the connection
  connection.reset();
}

Prevention

When it happens

Trigger: Feeding the ALTS frame parser bytes whose 4-byte length prefix decodes below the message-type header size (including 0/negative) or above MAX_DATA_LENGTH — i.e. desynchronized stream, corrupted framing, or wrong protocol bytes fed to the parser.

Common situations: Handshaker/transport byte-stream corruption, an off-by-N misalignment while copying frame bytes, or piping a non-ALTS stream into the ALTS frame parser in unit tests.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/bb56649b27de7de8. Report an issue: GitHub.

Appendix: source

Thrown at alts/src/main/java/io/grpc/alts/internal/AltsFraming.java:287

      if (isComplete) {
        return true;
      }

      // Read enough bytes to determine the length
      while (buffer.position() < FRAME_LENGTH_HEADER_SIZE && input.hasRemaining()) {
        buffer.put(input.get());
      }

      // If we have enough bytes to determine the length, read the length and ensure that our
      // internal buffer is large enough.
      if (buffer.position() == FRAME_LENGTH_HEADER_SIZE && input.hasRemaining()) {
        ByteBuffer bufferAlias = buffer.duplicate();
        ((Buffer) bufferAlias).flip();
        bufferAlias.order(ByteOrder.LITTLE_ENDIAN);
        int dataLength = bufferAlias.getInt();
        if (dataLength < FRAME_MESSAGE_TYPE_HEADER_SIZE || dataLength > MAX_DATA_LENGTH) {
          throw new IllegalArgumentException("Invalid frame length " + dataLength);
        }
        // Maybe resize the buffer
        int frameLength = dataLength + FRAME_LENGTH_HEADER_SIZE;
        if (buffer.capacity() < frameLength) {
          buffer = ByteBuffer.allocate(frameLength);
          buffer.order(ByteOrder.LITTLE_ENDIAN);
          buffer.putInt(dataLength);
        }
        ((Buffer) buffer).limit(frameLength);
      }

      // TODO: Similarly extract and check message type.

      // Read the remaining data into the internal buffer.
      copy(buffer, input);
      if (!buffer.hasRemaining()) {
        ((Buffer) buffer).flip();
        isComplete = true;

View on GitHub (pinned to 64daddc1f3)