aeron-io/aeron · error · IllegalArgumentException

counter id is not allocated, state

Error message

counter id <counterId> is not allocated, state: <state>

What it means

Thrown by Aeron counter metadata APIs (e.g. setting/updating a counter label) when the given counterId's metadata record is not in RECORD_ALLOCATED state. Aeron validates that a counter was actually allocated via a Counter/CounterManager before its metadata can be mutated. The state value in the message shows the raw metadata record state (e.g. RECORD_UNUSED=0, RECORD_RECLAIMED).

Solutions

  1. Obtain the counterId from the Counter instance returned by Aeron.addCounter() and use it before calling close()/free.
  2. Verify the counter is still allocated: check its state via the counters reader (isAllocated / getCounterState) before mutating metadata.
  3. Audit for double-free logic: ensure the counter is not released by another thread or cleanup path before use.
  4. Wrap the call in try-catch for IllegalArgumentException and treat it as 'counter no longer allocated' if reclamation is expected in your design.

Example fix

// before
long id = 7; // guessed
aeron.counters().updateLabel(id, "new label");
// after
try (Counter counter = aeron.addCounter(1, "my counter")) {
    aeron.counters().updateLabel(counter.counterId(), "new label");
}
Defensive patterns

Strategy: validation

Validate before calling

if (counterId < 0 || !countersReader.isAllocated(counterId)) {
    throw new IllegalStateException("counter " + counterId + " not allocated");
}

Try / catch

try {
    aeronCounters.updateLabel(counterId, label);
} catch (IllegalArgumentException e) {
    // counter was freed or never allocated; re-acquire or skip
}

Prevention

When it happens

Trigger: Calling a public AeronCounters method (e.g. updateLabel/setLabel style APIs) with a counterId that was never allocated, or whose record was freed/reclaimed via a prior free/release call.

Common situations: Using a counter id from a closed Counter object; double-freeing then touching a counter; race where another thread frees the counter before the label update; passing a hardcoded or guessed counter id instead of one obtained from Counter.counterId().

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/AeronCounters.java:1606

     * {@link CountersReader#MAX_LABEL_LENGTH}.
     *
     * @param metaDataBuffer containing the counter metadata.
     * @param counterId      to append version info to.
     * @param value          to be appended to the label.
     * @return number of bytes that got appended.
     * @throws IllegalArgumentException if {@code counterId} is invalid or points to non-allocated counter.
     */
    public static int appendToLabel(
        final AtomicBuffer metaDataBuffer, final int counterId, final String value)
    {
        Objects.requireNonNull(metaDataBuffer);
        validateCounterId(metaDataBuffer, counterId);

        final int counterMetaDataOffset = metaDataOffset(counterId);
        final int state = metaDataBuffer.getIntVolatile(counterMetaDataOffset);
        if (RECORD_ALLOCATED != state)
        {
            throw new IllegalArgumentException("counter id " + counterId + " is not allocated, state: " + state);
        }

        final int existingLabelLength = metaDataBuffer.getInt(counterMetaDataOffset + LABEL_OFFSET);
        final int remainingLabelLength = MAX_LABEL_LENGTH - existingLabelLength;

        final int writtenLength = metaDataBuffer.putStringWithoutLengthAscii(
            counterMetaDataOffset + LABEL_OFFSET + SIZE_OF_INT + existingLabelLength,
            value,
            0,
            remainingLabelLength);
        if (writtenLength > 0)
        {
            metaDataBuffer.putIntRelease(
                counterMetaDataOffset + LABEL_OFFSET, existingLabelLength + writtenLength);
        }

        return writtenLength;
    }

View on GitHub (pinned to 6d60124e15)