{"record":{"id":"1a32758b02f673f7","repo":"aeron-io/aeron","slug":"active-counter-not-found-counterid","errorCode":null,"errorMessage":"active counter not found ${counterId}","messagePattern":"active counter not found (.+?)","errorType":"console","errorClass":"ClusterException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java","lineNumber":269,"sourceCode":"    {\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":251,"sourceCodeEnd":272,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java#L251-L272","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlong recId = recoveryState.getSnapshotRecordingId(counterId, serviceId);\n// after\nif (RecoveryState.findCounter(countersReader) != CountersReader.NULL_COUNTER_ID) {\n    long recId = recoveryState.getSnapshotRecordingId(counterId, serviceId);\n}","handlingStrategy":"validation","validationCode":"int found = RecoveryState.findCounter(countersReader);\nif (found == CountersReader.NULL_COUNTER_ID) {\n    // no active recovery state; skip query\n}","typeGuard":null,"tryCatchPattern":"try {\n    long id = recoveryState.getSnapshotRecordingId(counterId, serviceId);\n} catch (ClusterException e) {\n    if (e.getMessage().contains(\"active counter not found\")) {\n        // rediscover counterId via RecoveryState.findCounter\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["aeron","cluster","counter","recovery"],"backgroundTag":"resource-not-found","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"}