aeron-io/aeron · error · ClusterException
active counter not found
Error message
active counter not found ${counterId} What it means
getSnapshotRecordingId looks up the recovery-state counter by counterId in the CountersReader; if no active counter exists for that id (not found or freed), it throws this ClusterException instead of returning a recording id.
Solutions
- Only query recovery state during the recovery phase while the counter is alive.
- Refresh/rediscover the recovery-state counterId (e.g. via RecoveryState.findCounter) instead of caching it.
- Check that the counters file being read is the same one where recovery state was allocated (correct cluster directory).
- Guard with RecoveryState.hasCounter/counters reader lookup before calling.
Example fix
// before
long recId = recoveryState.getSnapshotRecordingId(counterId, serviceId);
// after
if (RecoveryState.findCounter(countersReader) != CountersReader.NULL_COUNTER_ID) {
long recId = recoveryState.getSnapshotRecordingId(counterId, serviceId);
} Defensive patterns
Strategy: validation
Validate before calling
int found = RecoveryState.findCounter(countersReader);
if (found == CountersReader.NULL_COUNTER_ID) {
// no active recovery state; skip query
} Try / catch
try {
long id = recoveryState.getSnapshotRecordingId(counterId, serviceId);
} catch (ClusterException e) {
if (e.getMessage().contains("active counter not found")) {
// rediscover counterId via RecoveryState.findCounter
} else {
throw e;
}
} Prevention
- Do not cache recovery-state counterIds across lifecycle phases.
- Query only during recovery while the counter is allocated.
- Confirm the cluster directory/mark file matches the counters file in use.
When it happens
Trigger: Calling RecoveryState.getSnapshotRecordingId with a counterId that is no longer allocated in the CountersReader — e.g. the recovery state counter was freed after recovery completed, or a stale/incorrect counterId was passed.
Common situations: Querying recovery state after recovery finished and the counter was released; service using a cached counterId across a cluster restart; race where the counter was freed while the service still held the id.
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
- exceeds max key length
- invalid state counter code
- Invalid role counter code
- failed to start service=<ctx.serviceId()> leadershipTermId=
- invalid serviceId for count of
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/1a32758b02f673f7.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java:269
{
final DirectBuffer buffer = counters.metaDataBuffer();
if (counters.getCounterState(counterId) == RECORD_ALLOCATED &&
counters.getCounterTypeId(counterId) == RECOVERY_STATE_TYPE_ID)
{
final int recordOffset = CountersReader.metaDataOffset(counterId);
final int serviceCount = buffer.getInt(recordOffset + KEY_OFFSET + SERVICE_COUNT_OFFSET);
if (serviceId < 0 || serviceId >= serviceCount)
{
throw new ClusterException("invalid serviceId " + serviceId + " for count of " + serviceCount);
}
return buffer.getLong(
recordOffset + KEY_OFFSET + SNAPSHOT_RECORDING_IDS_OFFSET + (serviceId * SIZE_OF_LONG));
}
throw new ClusterException("active counter not found " + counterId);
}
}
View on GitHub (pinned to 6d60124e15)