{"record":{"id":"d3c77cfbfd265c56","repo":"aeron-io/aeron","slug":"expected-schemaid-controlresponseadapter","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/ControlResponseAdapter.java","lineNumber":124,"sourceCode":"            decoder.initialTermId(),\n            decoder.segmentFileLength(),\n            decoder.termBufferLength(),\n            decoder.mtuLength(),\n            decoder.sessionId(),\n            decoder.streamId(),\n            decoder.strippedChannel(),\n            decoder.originalChannel(),\n            decoder.sourceIdentity());\n    }\n\n    void onFragment(final DirectBuffer buffer, final int offset, final int length, final Header header)\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                handleControlResponse(controlResponseListener, buffer, offset);\n                break;\n\n            case RecordingDescriptorDecoder.TEMPLATE_ID:\n                handleRecordingDescriptor(controlResponseListener, buffer, offset);\n                break;\n\n            case RecordingSignalEventDecoder.TEMPLATE_ID:\n                handleRecordingSignal(recordingSignalConsumer, buffer, offset);\n                break;\n        }\n    }\n","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/client/ControlResponseAdapter.java#L106-L142","documentation":"ControlResponseAdapter.onFragment decodes the SBE MessageHeader of each fragment on the control-response stream and throws ArchiveException if the schemaId is not the expected archive control protocol schema id. This guards the adapter against decoding non-archive-control payloads as control responses.","triggerScenarios":"onFragment is handed a fragment whose header schemaId != MessageHeaderDecoder.SCHEMA_ID: a mismatched client/server SBE schema version, foreign messages on the control-response stream, or a manually constructed/malformed buffer fed to the adapter.","commonSituations":"Version skew between aeron-archive jars (client vs server), routing unrelated application traffic to the archive control-response stream, classpath contamination with codecs generated from an older schema.","solutions":["Upgrade/downgrade aeron-archive so client and server share one schema version","Dedicate the control-response channel/stream to archive control traffic only","Rebuild with a clean classpath so generated codecs match MessageHeaderDecoder.SCHEMA_ID","Log the offending schemaId and templateId before rethrowing to identify the foreign publisher"],"exampleFix":"// before\nsubscription.handler(this::onFragment); // any stream traffic lands here\n\n// after\n// validate before invoking the adapter\nif (header.schemaId() == MessageHeaderDecoder.SCHEMA_ID) {\n    controlResponseAdapter.onFragment(buffer, offset, length, header);\n}","handlingStrategy":"validation","validationCode":"MessageHeaderDecoder h = new MessageHeaderDecoder().wrap(buffer, offset);\nif (h.schemaId() != MessageHeaderDecoder.SCHEMA_ID) { return; // skip foreign fragment\n}\ncontrolResponseAdapter.onFragment(buffer, offset, length, header);","typeGuard":"boolean validSchema(UnsafeBuffer buf, int offset) {\n    messageHeaderDecoder.wrap(buf, offset);\n    return messageHeaderDecoder.schemaId() == MessageHeaderDecoder.SCHEMA_ID;\n}","tryCatchPattern":"try {\n    controlResponseAdapter.onFragment(buffer, offset, length, header);\n} catch (ArchiveException e) {\n    if (e.getMessage().startsWith(\"expected schemaId=\")) {\n        log.error(\"schema mismatch; client/server aeron-archive versions differ\", e);\n    }\n}","preventionTips":["Keep client and archive server on the same release train","Dedicate control-response channels exclusively to archive traffic","Verify codec regeneration after any SBE schema change","Add a startup version handshake/log line to expose version skew early"],"tags":["sbe","schema","protocol-mismatch","aeron-archive"],"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"}