{"record":{"id":"a7b7271e4c97d6c5","repo":"aeron-io/aeron","slug":"unknown-session-or-token-timeout-for-replaytoken-replaytoken","errorCode":null,"errorMessage":"Unknown session or token timeout for replayToken=\" + replayToken","messagePattern":"Unknown session or token timeout for replayToken=\" \\+ replayToken","errorType":"exception","errorClass":"ArchiveException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/ControlSessionAdapter.java","lineNumber":1180,"sourceCode":"        }\n    }\n\n    private ControlSession setupSessionAndChannelForReplay(\n        final ChannelUri channelUri,\n        final long replayToken,\n        final long recordingId,\n        final long correlationId,\n        final long controlSessionId,\n        final int templateId,\n        final Image image)\n    {\n        final ControlSession controlSession;\n        if (channelUri.hasControlModeResponse() && Aeron.NULL_VALUE != replayToken)\n        {\n            controlSession = conductor.getReplaySession(replayToken, recordingId);\n            if (null == controlSession)\n            {\n                throw new ArchiveException(\"Unknown session or token timeout for replayToken=\" + replayToken);\n            }\n\n            channelUri.put(RESPONSE_CORRELATION_ID_PARAM_NAME, Long.toString(image.correlationId()));\n        }\n        else\n        {\n            controlSession = getControlSession(correlationId, controlSessionId, templateId, image);\n        }\n        return controlSession;\n    }\n\n    private ControlSession getControlSession(\n        final long correlationId, final long controlSessionId, final int templateId, final Image image)\n    {\n        final SessionInfo info = controlSessionByIdMap.get(controlSessionId);\n        if (null != info)\n        {\n            if (info.image != image)","sourceCodeStart":1162,"sourceCodeEnd":1198,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/ControlSessionAdapter.java#L1162-L1198","documentation":"When a connect request arrives on a MDC control-mode=response channel with a replayToken, the adapter looks up the corresponding replay session in the archive conductor via getReplaySession(replayToken, recordingId). If no session is registered for that token (unknown token or the token timed out), the connection cannot be correlated and an ArchiveException is thrown.","triggerScenarios":"Calling ArchiveClient with a replayToken whose replay session has already ended or was never created on that archive; reusing a token after its timeout; using a token issued by a different archive instance; long delay between token issuance and connect so the conductor's replay session expired.","commonSituations":"Client retries a connect long after the original replay finished; load balancer routes the connect to a different archive node than the one that issued the token; token typed/copied incorrectly; slow startup so the replay session timed out before connect.","solutions":["Use the replay token promptly after requesting the replay; if it expired, issue a new startReplay call to obtain a fresh token.","Ensure the connect goes to the same archive instance that issued the token (no cross-node routing unless state is shared).","Verify the recordingId paired with the token matches the replay session that was started.","Check archive conductor logs for session expiry to confirm a timeout versus an unknown token."],"exampleFix":"// before\nlong token = staleTokenFromPreviousRun;\narchive.connect(uri, token);\n// after\nlong token = archive.startReplay(recordingId, position, length, replayChannel, replayStreamId);\narchive.connect(uri, token); // use immediately","handlingStrategy":"retry","validationCode":"// use the token immediately after obtaining it\nlong token = archive.startReplay(recId, pos, len, ch, streamId);\nif (token == Aeron.NULL_VALUE) throw new IllegalStateException(\"no token issued\");","typeGuard":null,"tryCatchPattern":"try {\n    controlResponsePoller.resubmitResponseChannelSetup(uri, token);\n} catch (ArchiveException e) {\n    if (e.getMessage().startsWith(\"Unknown session\")) {\n        token = archive.startReplay(recId, pos, len, ch, streamId); // re-issue\n    }\n}","preventionTips":["Issue and consume replay tokens within the same call flow; never cache across runs.","Do not route archive connects through load balancers that can switch nodes.","Confirm the recordingId passed with the token matches the replay session."],"tags":["archive","replay-token","session-timeout","mdc"],"backgroundTag":"record-not-found","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}