{"record":{"id":"4fadf0607b7107cf","repo":"aeron-io/aeron","slug":"initial-ack-already-received-from-service-possible-duplicate","errorCode":null,"errorMessage":"initial ack already received from service: possible duplicate serviceId=<serviceId>","messagePattern":"initial ack already received from service: possible duplicate serviceId=<serviceId>","errorType":"exception","errorClass":"ClusterException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java","lineNumber":2720,"sourceCode":"\n            NodeControl.ToggleState.reset(nodeControlToggle);\n\n            return 1;\n        }\n\n        return 0;\n    }\n\n    private boolean appendAction(final ClusterAction action, final long timestamp, final int flags)\n    {\n        return logPublisher.appendClusterAction(leadershipTermId, timestamp, action, flags);\n    }\n\n    private void captureServiceAck(final long logPosition, final long ackId, final long relevantId, final int serviceId)\n    {\n        if (0 == ackId && NULL_VALUE != serviceClientIds[serviceId])\n        {\n            throw new ClusterException(\n                \"initial ack already received from service: possible duplicate serviceId=\" + serviceId);\n        }\n\n        serviceAckQueues[serviceId].offerLast(new ServiceAck(ackId, logPosition, relevantId));\n    }\n\n    private boolean tryCreateAppendPosition(final int logSessionId)\n    {\n        final CountersReader counters = aeron.countersReader();\n        final int counterId = RecordingPos.findCounterIdBySession(counters, logSessionId, archive.archiveId());\n        if (CountersReader.NULL_COUNTER_ID == counterId)\n        {\n            return false;\n        }\n\n        final long registrationId = counters.getCounterRegistrationId(counterId);\n        if (0 == registrationId)\n        {","sourceCodeStart":2702,"sourceCodeEnd":2738,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java#L2702-L2738","documentation":"captureServiceAck records the first (ackId==0) ack from each clustered service, keyed by serviceId. If a second initial ack arrives for a service that already recorded one, the internal invariant (exactly one initial ack per service) is violated, so ClusterException is thrown.","triggerScenarios":"Thrown when ackId is 0 and serviceClientIds[serviceId] is not NULL_VALUE, i.e. a duplicate ackId=0 ack from the same serviceId.","commonSituations":"Two services configured with the same serviceId; a service container restarted and re-sent its initial ack; a misbehaving or buggy custom ClusteredService sending duplicate acks.","solutions":["Ensure each ClusteredService in the configuration has a unique serviceId","Check that service containers are not started twice against the same cluster","Review custom ClusteredService implementations for duplicate ack(AckId 0) sends","Restart the node cleanly if a partially-restarted container left stale ack state"],"exampleFix":"// before: duplicate serviceId across services\nClusteredServiceContainer.Configuration.serviceId(0); // service A\nClusteredServiceContainer.Configuration.serviceId(0); // service B\n\n// after: unique ids\nClusteredServiceContainer.Configuration.serviceId(0); // service A\nClusteredServiceContainer.Configuration.serviceId(1); // service B","handlingStrategy":"validation","validationCode":"// validate unique serviceIds at startup\nSet<Integer> ids = new HashSet<>();\nfor (ClusteredServiceContainer.Context c : serviceContexts)\n{\n    if (!ids.add(c.serviceId()))\n    {\n        throw new IllegalArgumentException(\"duplicate serviceId: \" + c.serviceId());\n    }\n}","typeGuard":null,"tryCatchPattern":"catch (ClusterException e)\n{\n    if (e.getMessage().contains(\"duplicate serviceId\"))\n    {\n        log.error(\"Configuration error: two services share one serviceId\", e);\n    }\n    throw e;\n}","preventionTips":["Assign each ClusteredService a distinct serviceId in configuration","Never start the same service container twice against one cluster","Audit custom services for duplicate initial acks"],"tags":["aeron","cluster","service-ack","duplicate","invariant"],"backgroundTag":"internal-invariant-violation","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"}