aeron-io/aeron · error · ClusterException

invalid state counter code

Error message

invalid state counter code: ${code}

What it means

ConsensusModule.State.get maps a counter code to a State enum value and rejects codes outside the valid range [0, STATES.length-1] with ClusterException "invalid state counter code". The code comes from the consensus module's status counter, so an out-of-range code means the counter was corrupted or written by an incompatible component.

Solutions

  1. Verify you read the counter's value, not its registration/counter id, before mapping to State.
  2. Ensure the Aeron driver and cluster versions match across all components.
  3. Check that no other process is writing to the consensus module status counter.
  4. If counters come from a corrupted mark/counters file, stop the node and clear the Aeron directory (aeron.directory.delete.on.start=true) before restart.

Example fix

// before
long code = counter.counterId(); // wrong: id, not value
State state = ConsensusModule.State.get(code);
// after
long code = counter.get(); // actual counter value
if (code >= 0 && code < ConsensusModule.State.values().length)
{
    State state = ConsensusModule.State.get(code);
}
Defensive patterns

Strategy: validation

Validate before calling

long code = counter.get();
if (code < 0 || code >= ConsensusModule.State.values().length)
{
    throw new IllegalStateException("invalid state counter code: " + code);
}

Type guard

boolean isValidStateCode(long code)
{
    return code >= 0 && code < ConsensusModule.State.values().length;
}

Try / catch

try
{
    State state = ConsensusModule.State.get(code);
}
catch (ClusterException ex)
{
    if (!ex.getMessage().startsWith("invalid state counter code")) throw ex;
    // re-read the counter value; check driver/agent version alignment
}

Prevention

When it happens

Trigger: Reading the consensus module's status counter (CounterListener / get(code)) where the counter value is negative or greater than the number of defined States (e.g. reading a counter Id instead of its value, or a counter written by a different Aeron version).

Common situations: Application code reading the wrong counter (using counterId as the code); stale/corrupted counters left in a reused Aeron directory; mixing Aeron versions between the media driver and cluster where state encodings differ; agents aggregating counters incorrectly.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModule.java:232

            {
                return CLOSED;
            }

            return get(counter.get());
        }

        /**
         * Get the {@link State} corresponding to a particular code.
         *
         * @param code representing a {@link State}.
         * @return the {@link State} corresponding to the provided code.
         * @throws ClusterException if the code does not correspond to a valid State.
         */
        public static State get(final long code)
        {
            if (code < 0 || code > (STATES.length - 1))
            {
                throw new ClusterException("invalid state counter code: " + code);
            }

            return STATES[(int)code];
        }

        /**
         * Get the current state of the {@link ConsensusModule}.
         *
         * @param counters  to search within.
         * @param clusterId to which the allocated counter belongs.
         * @return the state of the ConsensusModule or null if not found.
         */
        public static State find(final CountersReader counters, final int clusterId)
        {
            final int counterId = ClusterCounters.find(counters, CONSENSUS_MODULE_STATE_TYPE_ID, clusterId);
            if (Aeron.NULL_VALUE != counterId)
            {
                return State.get(counters.getCounterValue(counterId));

View on GitHub (pinned to 6d60124e15)