oracle/graal · error · IllegalArgumentException
String too long to encode, %s bytes
Error message
String too long to encode, %s bytes
What it means
BinaryOutput.writeUTF first walks the string to compute the modified-UTF-8 byte length (1 byte for U+0001..U+007F, 2 for U+0080..U+07FF and NUL/surrogates, 3 above). If the total exceeds MAX_LENGTH it throws IllegalArgumentException('String too long to encode, %d bytes') before writing anything. The wire format's length header (short, or the LARGE_STRING_TAG int header) cannot represent more than MAX_LENGTH bytes.
Source
Thrown at compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryOutput.java:197
public final void writeUTF(String string) throws IllegalArgumentException {
int len = string.length();
long utfLen = 0;
int c;
int count = 0;
for (int i = 0; i < len; i++) {
c = string.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
utfLen++;
} else if (c > 0x07FF) {
utfLen += 3;
} else {
utfLen += 2;
}
}
if (utfLen > MAX_LENGTH) {
throw new IllegalArgumentException("String too long to encode, " + utfLen + " bytes");
}
int headerSize;
if (utfLen > MAX_SHORT_LENGTH) {
headerSize = Integer.BYTES;
ensureBufferSize(headerSize, (int) utfLen);
tempDecodingBuffer[count++] = (byte) ((LARGE_STRING_TAG | (utfLen >>> 24)) & 0xff);
tempDecodingBuffer[count++] = (byte) ((utfLen >>> 16) & 0xFF);
} else {
headerSize = Short.BYTES;
ensureBufferSize(headerSize, (int) utfLen);
}
tempDecodingBuffer[count++] = (byte) ((utfLen >>> 8) & 0xFF);
tempDecodingBuffer[count++] = (byte) (utfLen & 0xFF);
int i = 0;
for (; i < len; i++) {
c = string.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Chunk the payload: split into segments under MAX_LENGTH, write count + segments, and reassemble on read.
- Pass large text out-of-band (e.g. via an object handle or file) and send only a reference.
- Compute the encoded length up front with the same 1/2/3-byte rule and reject oversized inputs early.
- Compress the string before marshalling if it is compressible and must stay inline.
Example fix
// before
out.writeUTF(hugeSource);
// after (chunked transfer)
int CHUNK = 1 << 16;
for (int i = 0; i < hugeSource.length(); i += CHUNK) {
out.writeUTF(hugeSource.substring(i, Math.min(hugeSource.length(), i + CHUNK)));
} Defensive patterns
Strategy: validation
Validate before calling
// Compute encoded size with the same rule as writeUTF before sending
long utfLen = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
utfLen += (c >= 0x0001 && c <= 0x007F) ? 1 : (c > 0x07FF ? 3 : 2);
}
if (utfLen > MAX_LENGTH) { /* chunk or send out-of-band */ } Try / catch
try {
out.writeUTF(s);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("String too long to encode")) {
// fall back to chunked transfer of substrings
}
} Prevention
- Never marshal unbounded strings inline; chunk by encoded size
- Send large payloads out-of-band via handles or files
- Bound string inputs at the API boundary
When it happens
Trigger: Marshalling a string whose encoded length exceeds the protocol's MAX_LENGTH across the libgraal/Truffle boundary via writeUTF — e.g. serializing source code, generated code text, or a large identifier payload as one string.
Common situations: Sending whole files, big generated snippets, or deeply nested stringified ASTs through the binary channel instead of chunking; tests with oversized synthetic strings after a format change lowered MAX_LENGTH.
Related errors
- Partial character at end
- malformed input: partial character at end
- malformed input around byte %d
- 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/3db53b438af73e71.
Report an issue: GitHub.