{"record":{"id":"ee0ca0d4d2e047d3","repo":"aeron-io/aeron","slug":"reentrant-calls-not-permitted-during-callbacks","errorCode":null,"errorMessage":"reentrant calls not permitted during callbacks","messagePattern":"reentrant calls not permitted during callbacks","errorType":"exception","errorClass":"AeronException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/client/AeronArchive.java","lineNumber":2607,"sourceCode":"        final State currentState = state;\n        if (State.CONNECTED != currentState)\n        {\n            if (State.CLOSED == currentState)\n            {\n                throw new ArchiveException(\"client is closed\");\n            }\n            else\n            {\n                close();\n            }\n        }\n    }\n\n    private void ensureNotReentrant()\n    {\n        if (isInCallback)\n        {\n            throw new AeronException(\"reentrant calls not permitted during callbacks\");\n        }\n    }\n\n    private void state(final State newState)\n    {\n        if (State.CLOSED != state)\n        {\n            state = newState;\n        }\n    }\n\n    /**\n     * Common configuration properties for communicating with an Aeron archive.\n     */\n    @Config(existsInC = false)\n    public static final class Configuration\n    {\n        private Configuration()","sourceCodeStart":2589,"sourceCodeEnd":2625,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/client/AeronArchive.java#L2589-L2625","documentation":"AeronArchive serializes access to its control protocol state machine. While the client is inside a callback (e.g. an AeronFragmentHandler or ControlResponsePoller handler it invoked), reentering AeronArchive API methods would corrupt the state machine, so ensureNotReentrant() throws this AeronException.","triggerScenarios":"From inside a callback delivered by AeronArchive (e.g. the controlResponsePoller's fragment handler or a recording signal handler), calling back into AeronArchive methods such as pollForNextResponse, nextCorrelationId, or send/receive operations.","commonSituations":"Dispatching work from an archive callback and immediately issuing new archive requests in the same callback; nested await*() calls inside a handler; legacy code updated to a version that added the reentrancy guard.","solutions":["Do not call AeronArchive methods from within its callbacks; record the event in a queue and process it after the callback returns.","Use a separate thread (e.g. an Agent/executor) to issue follow-up archive requests.","Restructure the callback to only mutate local state; run the next archive command in your own driver loop after the poll returns.","If truly needing reentrancy, use distinct AeronArchive instances for the callback path and the request path."],"exampleFix":"// before\narchive.listRecording(archive.listRecordings(0, 10)[0].recordingId()); // inside an archive callback\n// after\npendingRequests.offer(recordingId); // handled after callback returns on same thread\nlong id = pendingRequests.poll();\nif (id > 0) { archive.listRecording(id); }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { archive.pollForNextResponse(correlationId); } catch (AeronException e) { if (e.getMessage().contains(\"reentrant\")) { log.warn(\"archive call from inside callback; defer it\"); deferred.offer(() -> archive.pollForNextResponse(correlationId)); } }","preventionTips":["Never call AeronArchive methods from within its own callbacks; enqueue work for after the callback.","Use a queue + same-thread drain loop after poll returns to issue follow-up commands.","Keep callback bodies short and side-effect-free with respect to the archive client.","Document the no-reentrancy contract wherever archive callbacks are registered."],"tags":["aeron","archive","reentrancy","callback"],"backgroundTag":"invalid-state-transition","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}