oracle/graal · error · IllegalArgumentException

malformed input around byte %d

Error message

malformed input around byte %d

What it means

While decoding a 2-byte UTF-8 sequence, BinaryInput checks that the continuation byte has the 10xxxxxx pattern ((c2 & 0xC0) == 0x80). A violation throws IllegalArgumentException('malformed input around byte N') with the 1-based position of the bad byte. This is strict decoder validation copied from DataInputStream-style modified UTF-8 handling.

Source

Thrown at compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryInput.java:293

                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    byteCount++;
                    tempEncodingCharBuffer[charCount++] = (char) c1;
                    break;
                case 12:
                case 13:
                    /* 110x xxxx 10xx xxxx */
                    byteCount += 2;
                    if (byteCount > len) {
                        throw new IllegalArgumentException("Partial character at end");
                    }
                    c2 = tempEncodingByteBuffer[byteCount - 1];
                    if ((c2 & 0xC0) != 0x80) {
                        throw new IllegalArgumentException("malformed input around byte " + byteCount);
                    }
                    tempEncodingCharBuffer[charCount++] = (char) (((c1 & 0x1F) << 6) | (c2 & 0x3F));
                    break;
                case 14:
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    byteCount += 3;
                    if (byteCount > len) {
                        throw new IllegalArgumentException("malformed input: partial character at end");
                    }
                    c2 = tempEncodingByteBuffer[byteCount - 2];
                    c3 = tempEncodingByteBuffer[byteCount - 1];
                    if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) {
                        throw new IllegalArgumentException("malformed input around byte " + (byteCount - 1));
                    }
                    tempEncodingCharBuffer[charCount++] = (char) (((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
                    break;
                default:
                    /* 10xx xxxx, 1111 xxxx */

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Ensure the string was written by BinaryOutput.writeUTF (modified UTF-8, no plain 4-byte UTF-8 sequences).
  2. Check stream alignment: verify the preceding reads consumed exactly the bytes they declared (tags, lengths).
  3. Regenerate the marshalled data with matching producer/consumer versions.
  4. Avoid hand-constructing the binary format; always use BinaryOutput/BinaryInput pairs.
Defensive patterns

Strategy: validation

Try / catch

try {
    String s = in.readUTF();
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("malformed input around byte")) {
        // treat record as corrupt: reset stream position, skip or re-transfer
    }
}

Prevention

When it happens

Trigger: readUTF encountering a lead byte 110xxxxx followed by a byte that is not a continuation byte (e.g. ASCII byte or another lead byte) inside the string payload.

Common situations: Bytes were produced by a different encoder (standard UTF-8 with surrogate pairs vs modified UTF-8), memory corruption on the native side, or stream misalignment where readUTF starts at the wrong offset after a previous malformed record.

Understand the failure class

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/8cbdcb8200537fdb. Report an issue: GitHub.