apache/flink · error · IndexOutOfBoundsException

offset: {} len: {} value.len: {}

Error message

offset: {} len: {} value.len: {}

What it means

setValue(CharSequence value, int offset, int len) validates the substring range and throws IndexOutOfBoundsException on negative offset/len or when offset > value.length() - len (range past the end). Note the message has a long-standing bug: it prints 'value.len: ' + len instead of value.length(), so the reported value.len is actually the requested length — do not trust it for diagnosis.

Source

Thrown at flink-core/src/main/java/org/apache/flink/types/StringValue.java:199

     * @param offset The position to start the substring.
     * @param len The length of the substring.
     */
    public void setValue(StringValue value, int offset, int len) {
        checkNotNull(value);
        setValue(value.value, offset, len);
    }

    /**
     * Sets the value of the StringValue to a substring of the given string.
     *
     * @param value The new string value.
     * @param offset The position to start the substring.
     * @param len The length of the substring.
     */
    public void setValue(CharSequence value, int offset, int len) {
        checkNotNull(value);
        if (offset < 0 || len < 0 || offset > value.length() - len) {
            throw new IndexOutOfBoundsException(
                    "offset: " + offset + " len: " + len + " value.len: " + len);
        }

        ensureSize(len);
        this.len = len;
        for (int i = 0; i < len; i++) {
            this.value[i] = value.charAt(offset + i);
        }
        this.hashCode = 0;
    }

    /**
     * Sets the contents of this string to the contents of the given <tt>CharBuffer</tt>. The
     * characters between the buffer's current position (inclusive) and the buffer's limit
     * (exclusive) will be stored in this string.
     *
     * @param buffer The character buffer to read the characters from.
     */

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Validate offset >= 0 && len >= 0 && offset + len <= value.length() before the call
  2. Prefer setValue(value.subSequence(offset, offset + len).toString()) if bounds come from untrusted computation
  3. Remember the exception's value.len field is bogus; log value.length() yourself

Example fix

// before
sv.setValue(text, start, width); // start+width may exceed text.length()

// after
int end = Math.min(start + width, text.length());
sv.setValue(text, start, end - start);
Defensive patterns

Strategy: validation

Validate before calling

if (offset < 0 || len < 0 || offset > value.length() - len) {
    throw new IllegalArgumentException("substring [" + offset + "," + (offset + len) + ") vs length " + value.length());
}
sv.setValue(value, offset, len);

Try / catch

catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException("Bad substring range", e); }

Prevention

When it happens

Trigger: Calling setValue(seq, offset, len) with offset+len exceeding seq.length(), a negative offset, or a negative len; common when computing substrings from lengths derived elsewhere (e.g. parser positions).

Common situations: Parser/lexer code carrying offsets past the input end; off-by-one in loop bounds; reusing an offset variable after the source string changed to a shorter one.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/a461ea67fcba76b6. Report an issue: GitHub.