{"record":{"id":"858f32ac871f0c42","repo":"aeron-io/aeron","slug":"incompatible-app-version-semanticversion-tostring-ctx","errorCode":null,"errorMessage":"incompatible app version: ${SemanticVersion.toString(ctx.appVersion())} snapshot=${SemanticVersion.toString(appVersion)}","messagePattern":"incompatible app version: (.+?) snapshot=(.+?)","errorType":"console","errorClass":"ClusterException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/service/ClusteredServiceAgent.java","lineNumber":980,"sourceCode":"                break;\n            }\n\n            if (0 == fragments)\n            {\n                archive.checkForErrorResponse();\n                if (image.isClosed())\n                {\n                    throw new ClusterException(\"snapshot ended unexpectedly: \" + image);\n                }\n            }\n\n            idle(fragments);\n        }\n\n        final int appVersion = snapshotLoader.appVersion();\n        if (!ctx.appVersionValidator().isVersionCompatible(ctx.appVersion(), appVersion))\n        {\n            throw new ClusterException(\n                \"incompatible app version: \" + SemanticVersion.toString(ctx.appVersion()) +\n                \" snapshot=\" + SemanticVersion.toString(appVersion));\n        }\n\n        timeUnit = snapshotLoader.timeUnit();\n    }\n\n    private long onTakeSnapshot(final long logPosition, final long leadershipTermId)\n    {\n        try (AeronArchive archive = AeronArchive.connect(ctx.archiveContext().clone());\n            ExclusivePublication publication = aeron.addExclusivePublication(\n                ctx.snapshotChannel(), ctx.snapshotStreamId()))\n        {\n            final String channel = ChannelUri.addSessionId(ctx.snapshotChannel(), publication.sessionId());\n            archive.startRecording(channel, ctx.snapshotStreamId(), LOCAL, true);\n            final CountersReader counters = aeron.countersReader();\n            final int counterId = awaitRecordingCounter(publication.sessionId(), counters, archive);\n            final long recordingId = RecordingPos.getRecordingId(counters, counterId);","sourceCodeStart":962,"sourceCodeEnd":998,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/service/ClusteredServiceAgent.java#L962-L998","documentation":"Thrown as ClusterException when the appVersion stored in the loaded snapshot is not compatible (per the configured appVersionValidator) with the container's configured appVersion. It prevents loading snapshots written by an incompatible application version, guarding state format changes across releases.","triggerScenarios":"Restoring a cluster from a snapshot whose recorded appVersion fails ctx.appVersionValidator().isVersionCompatible(ctx.appVersion(), snapshotVersion); deploying a new release against old snapshots; changing the default appVersion without a compatible validator.","commonSituations":"Rolling upgrades/rollbacks where the old snapshot predates a state format change; forgetting to bump or set aeron.cluster.app.version; custom validator rejecting a minor-version mismatch.","solutions":["Update the configured appVersion (aeron.cluster.app.version) or the appVersionValidator to accept the snapshot's version","Write a fresh snapshot with the new application version before retiring the old one (take a snapshot before upgrade)","Restore from a snapshot produced by a compatible version, or replay the log from an earlier point","Implement SemanticVersion-based compatibility (same major, snapshot minor <= current) in your validator"],"exampleFix":"// before\ncontainer.context().appVersion(0x00010000); // 1.0, snapshot is 2.0\n// after\ncontainer.context().appVersion(0x00020000)\n         .appVersionValidator((configVersion, snapshotVersion) ->\n             SemanticVersion.major(snapshotVersion) <= SemanticVersion.major(configVersion));","handlingStrategy":"validation","validationCode":"int snapshotVersion = snapshotLoader.appVersion();\nif (!ctx.appVersionValidator().isVersionCompatible(ctx.appVersion(), snapshotVersion)) {\n    throw new IllegalStateException(\"snapshot appVersion \" + snapshotVersion + \" incompatible with \" + ctx.appVersion());\n}","typeGuard":null,"tryCatchPattern":"try { loadSnapshot(in); } catch (ClusterException ex) { /* restore from a compatible snapshot instead */ }","preventionTips":["Set aeron.cluster.app.version on every release that changes service state format","Always take a fresh snapshot with the new version before decommissioning old members","Encode version compatibility (major-match) in a custom appVersionValidator and test upgrades"],"tags":["aeron","cluster","versioning","snapshot"],"backgroundTag":"incompatible-source-type","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"}