aeron-io/aeron · error · IllegalArgumentException

lengthTwo < 0

Error message

lengthTwo < 0: {lengthTwo}

What it means

Thrown by Publication.validateAndComputeLength when lengthTwo is negative in a vectored (two-buffer) offer. The helper checks both component lengths before summing them, so the second buffer's length must also be non-negative.

Solutions

  1. Validate lengthTwo >= 0 before the vectored offer call.
  2. Ensure the second buffer is in read mode (flip() after writes) before computing its length.
  3. Add boundary assertions where the two lengths are derived so negative values cannot reach offer().

Example fix

// before
int bodyLen = bodyEnd - bodyStart; // negative when bodyStart > bodyEnd
publication.offer(header, 0, headerLen, body, 0, bodyLen);

// after
int bodyLen = bodyEnd - bodyStart;
if (bodyLen < 0)
{
    throw new IllegalArgumentException("invalid body length: " + bodyLen);
}
publication.offer(header, 0, headerLen, body, 0, bodyLen);
Defensive patterns

Strategy: validation

Validate before calling

if (lengthTwo < 0) { throw new IllegalArgumentException("second buffer length must be >= 0, got " + lengthTwo); }

Type guard

boolean isValidSecondLength(int lengthTwo) { return lengthTwo >= 0; }

Try / catch

try
{
    publication.offer(buf1, off1, len1, buf2, off2, len2);
}
catch (IllegalArgumentException e)
{
    // negative lengthTwo: correct the payload buffer sizing logic
    log.error("invalid vectored offer", e);
}

Prevention

When it happens

Trigger: publication.offer(bufferOne, offsetOne, lengthOne, bufferTwo, offsetTwo, lengthTwo) with lengthTwo < 0 — commonly a negative remaining() on the second buffer or a miscomputed payload length.

Common situations: Header+payload sends where the payload buffer wasn't flipped; deserialized length fields applied directly as buffer lengths; slicing errors producing inverted offsets on the second buffer.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/61cf990c5732a3ae. Report an issue: GitHub.

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/Publication.java:726

    final void checkMaxMessageLength(final int length)
    {
        if (length > maxMessageLength)
        {
            throw new IllegalArgumentException(
                "message exceeds maxMessageLength of " + maxMessageLength + ", length=" + length);
        }
    }

    static int validateAndComputeLength(final int lengthOne, final int lengthTwo)
    {
        if (lengthOne < 0)
        {
            throw new IllegalArgumentException("lengthOne < 0: " + lengthOne);
        }

        if (lengthTwo < 0)
        {
            throw new IllegalArgumentException("lengthTwo < 0: " + lengthTwo);
        }

        final int totalLength = lengthOne + lengthTwo;
        if (totalLength < 0)
        {
            throw new IllegalArgumentException("overflow totalLength=" + totalLength);
        }

        return totalLength;
    }

    /**
     * Returns a string representation of a position. Generally used for errors. If the position is a valid error then
     * String name of the error will be returned. If the value is 0 or greater the text will be "NONE". If the position
     * is negative, but not a known error code then "UNKNOWN" will be returned.
     *
     * @param position position value returned from a call to offer.
     * @return String representation of the error.

View on GitHub (pinned to 6d60124e15)