grpc/grpc-java · error · IllegalArgumentException

Invalid frame length ${dataLength}

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.

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)

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.