oracle/graal · error · IllegalArgumentException
Partial character at end
Error message
Partial character at end
What it means
BinaryInput.readUTF decodes the internal UTF-8-like stream used to marshal strings between Truffle/libgraal and its peer. When a 2-byte sequence (lead byte 110xxxxx) starts near the end of the buffer and its continuation byte is missing, it throws IllegalArgumentException('Partial character at end'). This mirrors java.io.DataInputStream's modified-UTF8 error semantics.
Source
Thrown at compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryInput.java:289
switch (c1 >> 4) {
case 0:
case 1:
case 2:
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));
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Verify producer and consumer use the same libgraal/Truffle marshalling format (same GraalVM version on both sides).
- Check that the byte count/header written by BinaryOutput.writeUTF matches what BinaryInput.readUTF consumes.
- Reproduce with logging around the read to confirm the buffer length is not truncated by an earlier short read.
- If the stream is corrupted, discard and regenerate the marshalled payload rather than retrying reads.
Defensive patterns
Strategy: validation
Validate before calling
// Verify buffer has room for the full sequence before readUTF // (framing sanity: header length must not exceed remaining bytes)
Try / catch
try {
String s = in.readUTF();
} catch (IllegalArgumentException e) {
if ("Partial character at end".equals(e.getMessage())) {
// truncated payload: request re-transfer of the whole record
}
} Prevention
- Always write strings with BinaryOutput.writeUTF so lengths are exact
- Verify transferred byte counts match headers
- Keep producer and consumer on the same GraalVM version
When it happens
Trigger: Reading a STRING-tagged value from a BinaryInput where the byte buffer is truncated mid multi-byte character: a mismatch between the declared payload length and the actual encoded string bytes.
Common situations: Corrupted or partially written marshalled data; a producer/consumer version mismatch changing the wire format; reading from a native memory buffer that was freed or resized mid-transfer.
Related errors
- malformed input: partial character at end
- malformed input around byte %d
- String too long to encode, %s bytes
- Unknown tag %d
- Len must be non negative but was %d
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/047ac355ac9544d7.
Report an issue: GitHub.