{"record":{"id":"f6e93eb9d6903f89","repo":"aeron-io/aeron","slug":"int-poller-relevantid","errorCode":"(int)poller.relevantId()","errorMessage":"poller.errorMessage()","messagePattern":"poller\\.errorMessage\\(\\)","errorType":"exception","errorClass":"ArchiveException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java","lineNumber":909,"sourceCode":"                {\n                    throw new TimeoutException(\"failed to get recording position\");\n                }\n\n                trackAction(NULL_VALUE);\n            }\n        }\n\n        return workCount;\n    }\n\n    private boolean hasResponse(final ControlResponsePoller poller)\n    {\n        if (poller.isPollComplete() && poller.controlSessionId() == srcArchive.controlSessionId())\n        {\n            final ControlResponseCode code = poller.code();\n            if (ControlResponseCode.ERROR == code)\n            {\n                throw new ArchiveException(poller.errorMessage(), (int)poller.relevantId());\n            }\n\n            return poller.correlationId() == activeCorrelationId && ControlResponseCode.OK == code;\n        }\n\n        return false;\n    }\n\n    private void error(final String msg, final int errorCode)\n    {\n        controlSession.sendErrorResponse(replicationId, errorCode, msg);\n    }\n\n    private void signal(final long position, final RecordingSignal recordingSignal)\n    {\n        final long subscriptionId = null != recordingSubscription ? recordingSubscription.registrationId() : NULL_VALUE;\n        controlSession.sendSignal(replicationId, dstRecordingId, subscriptionId, position, recordingSignal);\n    }","sourceCodeStart":891,"sourceCodeEnd":927,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java#L891-L927","documentation":"When a control response from the source archive arrives with code ERROR, ReplicationSession.hasResponse() rethrows it as an ArchiveException carrying the source archive's errorMessage and errorCode (taken from poller.relevantId()). This propagates any error the SOURCE archive produced while serving the replication (e.g. failed replay or recording-position request) to the destination side, failing the replication session.","triggerScenarios":"Any request ReplicationSession sends to the source archive (start replay via extendRecording/replay, getRecordingPosition, stopReplay) is rejected by the source archive; the poller observes an ERROR control response for the source control session and line 909 rethrows it.","commonSituations":"Requesting a replay of a recordingId that doesn't exist on the source; source archive rejecting an operation due to internal error or exhausted resources; version mismatch between the two Aeron archives; source recording deleted mid-replication.","solutions":["Read the embedded errorCode/errorMessage — it names the exact source-archive failure (e.g. UNKNOWN_RECORDING) and fix accordingly.","Confirm srcRecordingId exists on the source archive (listRecordings) before replicating.","Ensure both archives run compatible Aeron versions (control protocol must match).","Check source archive logs for the error reported against this control session/correlationId.","Retry the replication once the underlying source-side condition (deleted recording, resource exhaustion) is resolved."],"exampleFix":"// before\nfinal long replicationId = dstArchive.replication(srcRecordingId, channel);\n// after\ntry {\n    final long replicationId = dstArchive.replication(srcRecordingId, channel);\n} catch (ArchiverException e) {\n    if (e.errorCode() == ArchiveException.UNKNOWN_RECORDING) {\n        log.error(\"source recording \" + srcRecordingId + \" missing on source archive; skip replication\");\n    } else {\n        throw e;\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check the source recording exists before replicating to avoid the common UNKNOWN_RECORDING source error:\nlong count = countRecordings(sourceArchive, srcRecordingId);\nif (count == 0) throw new IllegalArgumentException(\"recordingId \" + srcRecordingId + \" not found on source archive\");","typeGuard":null,"tryCatchPattern":"try {\n    replicationId = archive.replication(srcRecordingId, channel);\n} catch (ArchiverException e) {\n    // errorCode/errorMessage are propagated verbatim from the source archive\n    log.error(\"source archive rejected replication: code=\" + e.errorCode() + \" msg=\" + e.getMessage());\n    handleSourceArchiveError(e.errorCode());\n}","preventionTips":["Always validate srcRecordingId against the source catalog before replication.","Keep both archives on the same Aeron version so control protocol codes match.","Monitor source archive error logs; any source-side error will abort replication.","Handle ArchiveException.errorCode() explicitly for known cases (UNKNOWN_RECORDING, GENERIC)."],"tags":["aeron-archive","replication","error-propagation","control-response"],"backgroundTag":"upstream-api-error","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"}