aeron-io/aeron · critical · ClusterException

mark file major version <SemanticVersion.major(version)>…

Error message

mark file major version <SemanticVersion.major(version)> does not match software: <MAJOR_VERSION>

What it means

When a ClusterMarkFile already exists on disk, its header's semantic version is checked; if the major version differs from the MAJOR_VERSION the running software expects, a ClusterException is thrown. This prevents a cluster component from running against state files written by an incompatible major release of the format.

Solutions

  1. Run the same (or format-compatible) Aeron version that created the existing mark file.
  2. If the old data is disposable, stop the cluster, back up, and delete the stale mark file from the cluster directory.
  3. Perform a proper upgrade path: drain/stop the old version's cluster cleanly before starting the new version.

Example fix

// before
# start v1.40 binary against directory written by v1.30
// after
# matching versions
mv cluster/cluster-mark-*.mark cluster/backup/  # only if state is expendable
# or run the binary version that matches the mark file
Defensive patterns

Strategy: validation

Validate before calling

// java: probe the mark file version before starting the component
try (ClusterMarkFile probe = new ClusterMarkFile(markFile, null, 0, epochClock, logger)) {
    int version = probe.version();
    if (SemanticVersion.major(version) != ClusterMarkFile.MAJOR_VERSION) {
        throw new IllegalStateException("stale mark file, major=" + SemanticVersion.major(version));
    }
} catch (NoSuchFileException ignore) { /* fresh start is fine */ }

Try / catch

try {
    startCluster();
} catch (ClusterException e) {
    if (e.getMessage().contains("mark file major version")) {
        // stop, archive the old mark file, or redeploy the matching version
    }
    throw e;
}

Prevention

When it happens

Trigger: Starting a consensus module or cluster service over a pre-existing cluster mark file (cluster-mark-0.mark etc.) whose header major version differs from the running binary's MAJOR_VERSION — e.g. after upgrading or downgrading Aeron.

Common situations: Aeron version upgrade without migrating/cleaning the cluster directory; rolling deployments with mixed versions; pointing a new binary at an old replay/archive directory.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/236bf5ed3c047b26. Report an issue: GitHub.

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/service/ClusterMarkFile.java:169

        {
            final int currentHeaderOffset = headerOffset(file);
            final MarkFile existingMarkFile = new MarkFile(
                file,
                true,
                currentHeaderOffset + MarkFileHeaderDecoder.versionEncodingOffset(),
                currentHeaderOffset + MarkFileHeaderDecoder.activityTimestampEncodingOffset(),
                totalFileLength,
                timeoutMs,
                epochClock,
                (version) ->
                {
                    if (VERSION_FAILED == version)
                    {
                        System.err.println("mark file version -1 indicates error on previous startup.");
                    }
                    else if (SemanticVersion.major(version) != MAJOR_VERSION)
                    {
                        throw new ClusterException("mark file major version " + SemanticVersion.major(version) +
                            " does not match software: " + MAJOR_VERSION);
                    }
                },
                null);
            final UnsafeBuffer existingBuffer = existingMarkFile.buffer();

            if (0 != currentHeaderOffset)
            {
                headerDecoder.wrapAndApplyHeader(existingBuffer, 0, messageHeaderDecoder);
            }
            else
            {
                headerDecoder.wrap(
                    existingBuffer, 0, MarkFileHeaderDecoder.BLOCK_LENGTH, MarkFileHeaderDecoder.SCHEMA_VERSION);
            }

            final ClusterComponentType existingType = headerDecoder.componentType();
            if (existingType != ClusterComponentType.UNKNOWN && existingType != type)

View on GitHub (pinned to 6d60124e15)