aeron-io/aeron · critical · ClusterException

incompatible time unit

Error message

incompatible time unit: <clusterTimeUnit> snapshot=<snapshotTimeUnit>

What it means

During snapshot load the consensus module checks that the snapshot's recorded cluster time unit matches the clusterTimeUnit the node is configured with. A mismatch is FATAL because timer and timestamp semantics would be silently wrong if the snapshot were loaded with a different time unit.

Solutions

  1. Align the node's clusterTimeUnit configuration with the time unit used by the snapshot.
  2. Take a new snapshot from a cluster running with the desired time unit before switching.
  3. Do not reuse snapshot directories across clusters that use different time units.
  4. Verify aeron.cluster.credentials / context time unit settings are identical on all nodes.

Example fix

// before
ctx.clusterTimeUnit(TimeUnit.NANOS); // snapshot was MILLIS
// after
ctx.clusterTimeUnit(TimeUnit.MILLISECONDS); // matches snapshot
Defensive patterns

Strategy: validation

Validate before calling

// before load
if (configuredClusterTimeUnit != snapshotTimeUnit) {
    throw new IllegalStateException("cluster time unit mismatch with snapshot: " + snapshotTimeUnit);
}

Try / catch

try { cluster.start(); } catch (ClusterException e) { if (e.getMessage().startsWith("incompatible time unit")) { reconfigureTimeUnitOrRestoreSnapshot(); } else { throw e; } }

Prevention

When it happens

Trigger: onLoadBeginSnapshot receives a TimeUnit that is not equal to the configured clusterTimeUnit, e.g. loading a snapshot taken by a cluster configured for MILLIS into a node configured for NANOS.

Common situations: Changing the cluster time unit configuration while keeping old snapshots; copying snapshot/marker data between clusters with different time unit settings; misconfigured ctx clusterTimeUnit on a new node.

Related errors


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

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java:645

    public ClusterMember clusterMember()
    {
        return thisMember;
    }

    public void onLoadBeginSnapshot(
        final int appVersion, final TimeUnit timeUnit, final DirectBuffer buffer, final int offset, final int length)
    {
        if (!ctx.appVersionValidator().isVersionCompatible(ctx.appVersion(), appVersion))
        {
            throw new ClusterException(
                "incompatible version: " + SemanticVersion.toString(ctx.appVersion()) +
                " snapshot=" + SemanticVersion.toString(appVersion),
                AeronException.Category.FATAL);
        }

        if (timeUnit != clusterTimeUnit)
        {
            throw new ClusterException(
                "incompatible time unit: " + clusterTimeUnit + " snapshot=" + timeUnit, AeronException.Category.FATAL);
        }
    }

    public ControlledFragmentHandler.Action onExtensionMessage(
        final int actingBlockLength,
        final int templateId,
        final int schemaId,
        final int actingVersion,
        final DirectBuffer buffer,
        final int offset,
        final int length,
        final Header header)
    {
        if (null != consensusModuleExtension)
        {
            return consensusModuleExtension.onIngressExtensionMessage(
                actingBlockLength, templateId, schemaId, actingVersion, buffer, offset, length, header);

View on GitHub (pinned to 6d60124e15)