aeron-io/aeron · critical · IllegalStateException

failed to find CandidateTerm entry

Error message

failed to find CandidateTerm entry

What it means

NodeStateFile.loadInitialState scans the node state file for a CandidateTerm SBE message by reading recorded offsets; the offset returned by candidateTermOffset() was Aeron.NULL_VALUE, meaning no CandidateTerm entry exists in the file. The library throws IllegalStateException because loading the initial state requires a CandidateTerm entry to decode, so the file is missing required content.

Solutions

  1. Verify the node state file being opened is intact and actually contains a CandidateTerm entry (check file size and that the member was a candidate at some point).
  2. If the file was created but never initialized, recreate/initialize it through the normal cluster lifecycle instead of loading it directly.
  3. Restore the file from a known-good backup of the cluster data directory.
  4. Confirm the Aeron version matches the one that wrote the file; regenerate state if upgrading across versions.

Example fix

// before
final NodeStateFile f = new NodeStateFile(ctx); f.loadInitialState(); // throws if no entry
// after
if (f.hasCandidateTermEntry()) { f.loadInitialState(); } else { recreateOrRestoreStateFile(); }
Defensive patterns

Strategy: try-catch

Validate before calling

if (nodeStateFile.file().length() == 0 || !hasCandidateTermEntryOnDisk(file)) { restoreFromBackup(); }

Try / catch

try { nodeStateFile.loadInitialState(); } catch (IllegalStateException e) { restoreStateFromBackupOrRejoinCluster(); }

Prevention

When it happens

Trigger: Calling NodeStateFile.loadInitialState() (via loadDecodersAndOffsets) on a node state file that has no CandidateTerm record — e.g. the file was created empty/truncated, the CandidateTerm entry was never appended, or the file is from an older format that never wrote one.

Common situations: Replaying a corrupted or partially-written node-state file after a cluster crash; pointing a replica at a state file produced by a different Aeron version; manually copying or truncating cluster data directories during backup/restore.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/NodeStateFile.java:202

            nodeStateHeaderDecoder.sbeBlockLength(),
            NodeStateFooterDecoder.TEMPLATE_ID,
            buffer,
            messageHeaderDecoder);

        if (Aeron.NULL_VALUE == footerOffset)
        {
            throw new IllegalStateException("failed to find NodeStateFooter entry, file corrupt?");
        }

        final int candidateTermOffset = scanForMessageTypeOffset(
            nodeStateHeaderDecoder.sbeBlockLength(),
            CandidateTermDecoder.TEMPLATE_ID,
            buffer,
            messageHeaderDecoder);

        if (Aeron.NULL_VALUE == candidateTermOffset)
        {
            throw new IllegalStateException("failed to find CandidateTerm entry");
        }

        candidateTermDecoder.wrapAndApplyHeader(buffer, candidateTermOffset, messageHeaderDecoder);
    }

    private static void initialiseDecodersOnCreation(
        final MutableDirectBuffer buffer,
        final NodeStateHeaderDecoder nodeStateHeaderDecoder,
        final MessageHeaderDecoder messageHeaderDecoder,
        final CandidateTermDecoder candidateTermDecoder)
    {
        final MessageHeaderEncoder messageHeaderEncoder = new MessageHeaderEncoder();

        nodeStateHeaderDecoder.wrap(
            buffer, 0, NodeStateHeaderDecoder.BLOCK_LENGTH, NodeStateHeaderDecoder.SCHEMA_VERSION);
        new NodeStateHeaderEncoder()
            .wrap(buffer, 0)
            .version(ClusterMarkFile.SEMANTIC_VERSION);

View on GitHub (pinned to 6d60124e15)