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

  1. Chunk the payload: split into segments under MAX_LENGTH, write count + segments, and reassemble on read.
  2. Pass large text out-of-band (e.g. via an object handle or file) and send only a reference.
  3. Compute the encoded length up front with the same 1/2/3-byte rule and reject oversized inputs early.
  4. 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

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


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