{"record":{"id":"8df75c3ffafa78cc","repo":"aeron-io/aeron","slug":"invalid-serviceid-serviceid-for-count-of-servicecount","errorCode":null,"errorMessage":"invalid serviceId ${serviceId} for count of ${serviceCount}","messagePattern":"invalid serviceId (.+?) for count of (.+?)","errorType":"validation","errorClass":"ClusterException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java","lineNumber":262,"sourceCode":"     *\n     * @param counters  to search within.\n     * @param counterId for the active recovery counter.\n     * @param serviceId for the snapshot required.\n     * @return the count of replay terms if found otherwise {@link Aeron#NULL_VALUE}.\n     */\n    public static long getSnapshotRecordingId(final CountersReader counters, final int counterId, final int serviceId)\n    {\n        final DirectBuffer buffer = counters.metaDataBuffer();\n\n        if (counters.getCounterState(counterId) == RECORD_ALLOCATED &&\n            counters.getCounterTypeId(counterId) == RECOVERY_STATE_TYPE_ID)\n        {\n            final int recordOffset = CountersReader.metaDataOffset(counterId);\n\n            final int serviceCount = buffer.getInt(recordOffset + KEY_OFFSET + SERVICE_COUNT_OFFSET);\n            if (serviceId < 0 || serviceId >= serviceCount)\n            {\n                throw new ClusterException(\"invalid serviceId \" + serviceId + \" for count of \" + serviceCount);\n            }\n\n            return buffer.getLong(\n                recordOffset + KEY_OFFSET + SNAPSHOT_RECORDING_IDS_OFFSET + (serviceId * SIZE_OF_LONG));\n        }\n\n        throw new ClusterException(\"active counter not found \" + counterId);\n    }\n}\n","sourceCodeStart":244,"sourceCodeEnd":272,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java#L244-L272","documentation":"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.","triggerScenarios":"Calling getSnapshotRecordingId(counterId, serviceId) where serviceId < 0 or serviceId >= the service count encoded in the recovery state counter key.","commonSituations":"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.","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)."],"exampleFix":"// before\nlong id = recoveryState.getSnapshotRecordingId(counterId, serviceId);\n// after\nif (serviceId >= 0 && serviceId < configuredServiceCount) {\n    long id = recoveryState.getSnapshotRecordingId(counterId, serviceId);\n}","handlingStrategy":"validation","validationCode":"if (serviceId < 0 || serviceId >= configuredServiceCount) {\n    throw new IllegalArgumentException(\"serviceId out of range: \" + serviceId);\n}","typeGuard":null,"tryCatchPattern":"try {\n    long id = recoveryState.getSnapshotRecordingId(counterId, serviceId);\n} catch (ClusterException e) {\n    if (e.getMessage().contains(\"invalid serviceId\")) {\n        // fix clusteredServiceId config or re-snapshot cluster\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["aeron","cluster","recovery","service-id"],"backgroundTag":"value-out-of-range","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}