{"record":{"id":"1ca161c16e067c53","repo":"aeron-io/aeron","slug":"expected-schemaid-recordingsignaladapter","errorCode":null,"errorMessage":"expected schemaId=","messagePattern":"expected schemaId=","errorType":"exception","errorClass":"ArchiveException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/client/RecordingSignalAdapter.java","lineNumber":112,"sourceCode":"    public boolean isDone()\n    {\n        return isDone;\n    }\n\n    private ControlledFragmentHandler.Action onFragment(\n        final DirectBuffer buffer, final int offset, final int length, final Header header)\n    {\n        if (isDone)\n        {\n            return ABORT;\n        }\n\n        messageHeaderDecoder.wrap(buffer, offset);\n\n        final int schemaId = messageHeaderDecoder.schemaId();\n        if (schemaId != MessageHeaderDecoder.SCHEMA_ID)\n        {\n            throw new ArchiveException(\"expected schemaId=\" + MessageHeaderDecoder.SCHEMA_ID + \", actual=\" + schemaId);\n        }\n\n        switch (messageHeaderDecoder.templateId())\n        {\n            case ControlResponseDecoder.TEMPLATE_ID:\n                controlResponseDecoder.wrap(\n                    buffer,\n                    offset + MessageHeaderDecoder.ENCODED_LENGTH,\n                    messageHeaderDecoder.blockLength(),\n                    messageHeaderDecoder.version());\n\n                if (controlResponseDecoder.controlSessionId() == controlSessionId)\n                {\n                    controlEventListener.onResponse(\n                        controlSessionId,\n                        controlResponseDecoder.correlationId(),\n                        controlResponseDecoder.relevantId(),\n                        controlResponseDecoder.code(),","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/client/RecordingSignalAdapter.java#L94-L130","documentation":"RecordingSignalAdapter.onFragment wraps the incoming SBE buffer as a MessageHeader and verifies the schemaId matches the archive protocol's MessageHeaderDecoder.SCHEMA_ID (1055). A mismatch means the fragment was not produced by the Aeron Archive control-protocol SBE schema, so decoding would be unsafe. The library throws ArchiveException to abort processing of the corrupted/foreign message.","triggerScenarios":"A fragment delivered to the control-response subscription whose first bytes are not an Archive SBE message header — e.g. the subscription is pointed at a publication sending raw/non-SBE payloads, a different SBE schema was used to encode, or a buffer offset bug causes the header to be read at the wrong position.","commonSituations":"Mixing Aeron versions where the archive schema id changed; a custom app publishing plain JSON/binary onto the channel that the RecordingSignalAdapter subscribes to; misconfigured replay/subscription URI receiving the wrong stream.","solutions":["Ensure only Aeron Archive control-protocol messages are published to the channel this adapter subscribes to","Use matching aeron-archive and aeron-client jar versions on sender and receiver so the SBE schema id is identical","Verify the fragment offset passed to the adapter comes directly from the Image/FragmentHandler (no manual offset arithmetic)","Regenerate codecs from the same aeron-archive aeron-archive-codecs version used by the archive"],"exampleFix":"// before: subscribing to a shared app channel\nAeron.addSubscription(\"aeron:udp?endpoint=app.com\", appStreamId, recordingSignalAdapter::onFragment);\n// after: dedicated archive control channel/stream\nAeron.addSubscription(\"aeron:udp?endpoint=localhost:8010\", archiveControlStreamId, recordingSignalAdapter::onFragment);","handlingStrategy":"try-catch","validationCode":"// verify the stream only carries archive control SBE messages and codecs match:\nif (messageHeaderDecoder.schemaId() != MessageHeaderDecoder.SCHEMA_ID) { /* route to dead-letter/log */ }","typeGuard":"boolean isArchiveSbeBuffer(DirectBuffer buffer, int offset) {\n    MessageHeaderDecoder h = new MessageHeaderDecoder();\n    h.wrap(buffer, offset);\n    return h.schemaId() == MessageHeaderDecoder.SCHEMA_ID;\n}","tryCatchPattern":"try { adapter.onFragment(buffer, offset, length, header); }\ncatch (ArchiveException e) { if (e.getMessage().startsWith(\"expected schemaId\")) { log.error(\"foreign message on control stream\", e); } }","preventionTips":["Keep aeron-archive codecs versions aligned across sender and receiver","Publish only archive control messages on the control channel","Never manually adjust fragment offsets before decoding"],"tags":["sbe","schema","aeron-archive","deserialization"],"backgroundTag":"schema-validation-failed","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"}