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
- Obtain the counterId from the Counter instance returned by Aeron.addCounter() and use it before calling close()/free.
- Verify the counter is still allocated: check its state via the counters reader (isAllocated / getCounterState) before mutating metadata.
- Audit for double-free logic: ensure the counter is not released by another thread or cleanup path before use.
- 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
- Always take counterId from Counter.counterId(), never hardcode
- Check CountersReader.isAllocated before metadata mutations
- Avoid touching counters after close/free; track lifecycle ownership
- Beware races: one thread freeing while another updates
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
- counter id is negative
- counter id out of range: 0 - maxCounterId=
- Counter not allocated: id=
- existing max write time counter detected for archiveId=
- client is closed
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)