aeron-io/aeron · error · IllegalArgumentException

name + " cannot be negative: value=" + value

Error message

name + " cannot be negative: value=" + value

What it means

CatalogIndex.ensurePositive throws IllegalArgumentException when a caller passes a negative value for a catalog index operation argument (e.g. recording id, position or offset used by add, remove, or recordingOffset). The Aeron Archive catalog requires non-negative identifiers and offsets, so negative values are rejected up front with the offending name and value in the message.

Solutions

  1. Validate arguments are >= 0 before calling add/remove/recordingOffset and map -1 sentinels to explicit 'not found' handling instead of passing them through
  2. Check arithmetic that produces the value for underflow; clamp or throw a domain-specific error when a computed position/offset goes negative
  3. Log the value and its source at the call site to find where the negative value originates
  4. Verify external inputs (config files, control requests, replay parameters) are parsed and range-checked before reaching the catalog index

Example fix

// before
long offset = stopPosition - startPosition; // can be negative if stop < start
catalogIndex.recordingOffset(recordingId, offset);
// after
long offset = stopPosition - startPosition;
if (offset < 0) { throw new IllegalArgumentException("stopPosition < startPosition for recordingId=" + recordingId); }
catalogIndex.recordingOffset(recordingId, offset);
Defensive patterns

Strategy: validation

Validate before calling

if (recordingId < 0) { throw new IllegalArgumentException("recordingId must be non-negative, got " + recordingId); }
if (offset < 0) { throw new IllegalArgumentException("offset must be non-negative, got " + offset); }
catalogIndex.recordingOffset(recordingId, offset);

Type guard

static boolean isNonNegative(long v) { return v >= 0L; }

Try / catch

try { catalogIndex.remove(recordingId); }
catch (IllegalArgumentException e) { if (e.getMessage().contains("cannot be negative")) { /* map to caller error */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling CatalogIndex.add, remove, or recordingOffset with a negative long argument, typically a recordingId, startPosition, or offset computed from a failed lookup (e.g. -1 sentinel) or an underflowed subtraction.

Common situations: Passing a -1 sentinel value returned by a failed recording-id lookup; subtracting positions where the minuend is smaller than the subtrahend; uninitialized long fields defaulted incorrectly; deserializing corrupt control or configuration values.

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/4c7b2010b0a7ecf0. Report an issue: GitHub.

Appendix: source

Thrown at aeron-archive/src/main/java/io/aeron/archive/CatalogIndex.java:221

        }

        return -1;
    }

    private static long[] expand(final long[] index)
    {
        final int length = index.length;
        final int entries = length >> 1;
        final int newLength = (entries + (entries >> 1)) << 1;

        return copyOf(index, newLength);
    }

    private static void ensurePositive(final long value, final String name)
    {
        if (value < 0L)
        {
            throw new IllegalArgumentException(name + " cannot be negative: value=" + value);
        }
    }
}

View on GitHub (pinned to 6d60124e15)