{"record":{"id":"d9729cf5f38dd7a1","repo":"aeron-io/aeron","slug":"failed-to-get-recording-position","errorCode":null,"errorMessage":"failed to get recording position","messagePattern":"failed to get recording position","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java","lineNumber":518,"sourceCode":"        }\n        else\n        {\n            final ControlResponsePoller poller = srcArchive.controlResponsePoller();\n            workCount += poller.poll();\n\n            if (hasResponse(poller))\n            {\n                srcRecordingPosition = poller.relevantId();\n                if (NULL_POSITION == srcRecordingPosition && null != liveDestination)\n                {\n                    throw new ArchiveException(\"cannot live merge without active source recording\");\n                }\n\n                state(State.EXTEND, \"\");\n            }\n            else if (epochClock.time() >= (timeOfLastActionMs + actionTimeoutMs))\n            {\n                throw new TimeoutException(\"failed to get recording position\");\n            }\n        }\n\n        return workCount;\n    }\n\n    private int extend()\n    {\n        final boolean isMds = isTagged || null != liveDestination;\n        final ChannelUri channelUri = ChannelUri.parse(replicationChannel);\n        final String endpoint = channelUri.get(CommonContext.ENDPOINT_PARAM_NAME);\n        channelUri.put(CommonContext.REJOIN_PARAM_NAME, \"false\");\n        if (!channelUri.hasControlModeResponse())\n        {\n            channelUri.put(CommonContext.SESSION_ID_PARAM_NAME, Integer.toString(replaySessionId));\n        }\n\n        if (isMds)","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java#L500-L536","documentation":"Thrown by ReplicationSession.srcRecordingPosition when the getRecordingPosition request was sent but the control response poller receives no relevant response from the source archive within actionTimeoutMs. Aeron throws TimeoutException to stop the replication rather than wait indefinitely on a stalled control channel. Like the other replication timeouts, it indicates the source archive's control response path is not delivering answers.","triggerScenarios":"Replication session waiting on the source archive's ControlResponsePoller; poller.poll() yields no response matching the outstanding correlation id before epochClock.time() exceeds timeOfLastActionMs + actionTimeoutMs — source archive conductor overloaded, response fragments lost, or timeout too small.","commonSituations":"Slow/WAN links between archives with default timeouts; source archive under heavy load delaying control responses; response-channel misconfiguration or packet loss; source archive restart that orphaned the outstanding correlation id.","solutions":["Verify the source archive is responsive (query it manually with AeronArchive.listRecordings from another client).","Increase the replication action timeout in the Archive client context.","Check the control response channel for loss/misconfiguration; use a reliable path for archive control traffic.","Retry the replication; repeated failure at this state points to a source-archive-side problem to diagnose with logs.","Keep Aeron up to date; control-response polling robustness has improved over releases."],"exampleFix":"// before\nctx.actionTimeoutNs(TimeUnit.SECONDS.toNanos(5));\n// after: allow for slow control responses on WAN replication\nctx.actionTimeoutNs(TimeUnit.SECONDS.toNanos(60));","handlingStrategy":"retry","validationCode":"// sanity-check the source archive answers control queries before replicating\ntry (AeronArchive probe = AeronArchive.connect(clientCtx)) {\n    probe.listRecordingsForUri(0, 1, recordingUriFragment, (cid, descriptors) -> {});\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.doWork();\n} catch (TimeoutException e) {\n    if (e.getMessage().contains(\"failed to get recording position\")) {\n        log.warn(\"no control response from source archive; retrying replication\");\n        restartReplicationWithBackoff();\n    }\n}","preventionTips":["Run a lightweight control query against the source archive as a readiness check before replication.","Increase actionTimeoutNs for WAN or loaded environments.","Monitor control response latency on the source archive.","Use reliable transport for archive control channels to avoid lost responses."],"tags":["aeron","archive","timeout","replication","control-channel"],"backgroundTag":"request-timeout","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"}