aeron-io/aeron · error · ClusterException
invalid serviceId for count of
Error message
invalid serviceId ${serviceId} for count of ${serviceCount} What it means
RecoveryState.getSnapshotRecordingId validates the requested serviceId against the serviceCount stored in the recovery-state counter's key. If serviceId is negative or >= serviceCount, this ClusterException is thrown — the caller asked for a snapshot recording ID for a service that was not recorded.
Solutions
- Ensure each service container's clusteredServiceId is within [0, serviceCount).
- Re-take a cluster snapshot after changing the number of services or their IDs.
- Validate serviceId against the configured service count before calling getSnapshotRecordingId.
- Check cluster configuration consistency across all nodes (service ids/counts must match the snapshot).
Example fix
// before
long id = recoveryState.getSnapshotRecordingId(counterId, serviceId);
// after
if (serviceId >= 0 && serviceId < configuredServiceCount) {
long id = recoveryState.getSnapshotRecordingId(counterId, serviceId);
} Defensive patterns
Strategy: validation
Validate before calling
if (serviceId < 0 || serviceId >= configuredServiceCount) {
throw new IllegalArgumentException("serviceId out of range: " + serviceId);
} Try / catch
try {
long id = recoveryState.getSnapshotRecordingId(counterId, serviceId);
} catch (ClusterException e) {
if (e.getMessage().contains("invalid serviceId")) {
// fix clusteredServiceId config or re-snapshot cluster
} else {
throw e;
}
} Prevention
- Keep clusteredServiceId within [0, serviceCount) on every node.
- Re-snapshot after changing service count or ids.
- Share one source of truth for service configuration across the cluster.
When it happens
Trigger: Calling getSnapshotRecordingId(counterId, serviceId) where serviceId < 0 or serviceId >= the service count encoded in the recovery state counter key.
Common situations: Service registered with an id higher than the configured service count (clusteredServiceId misconfiguration); snapshot taken with fewer services than are now querying recovery state; changed service configuration between snapshot and recovery.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- failed to start service=<ctx.serviceId()> leadershipTermId=
- service id outside allowed range
- exceeds max key length
- active counter not found
- not found in
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/8df75c3ffafa78cc.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java:262
*
* @param counters to search within.
* @param counterId for the active recovery counter.
* @param serviceId for the snapshot required.
* @return the count of replay terms if found otherwise {@link Aeron#NULL_VALUE}.
*/
public static long getSnapshotRecordingId(final CountersReader counters, final int counterId, final int serviceId)
{
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)