aeron-io/aeron · critical · IllegalStateException

failed to find NodeStateFooter entry, file corrupt?

Error message

failed to find NodeStateFooter entry, file corrupt?

What it means

After validating the header, loadInitialState scans the node-state file for a NodeStateFooter message to locate the remaining entries. If no footer entry exists (scan returns Aeron.NULL_VALUE), the file layout cannot be trusted and an IllegalStateException ('file corrupt?') is thrown.

Solutions

  1. Restore the node-state file from a known-good backup
  2. Delete the corrupt file and recreate it with createNew=true (loses prior state: candidate term etc.)
  3. Check the file size vs MINIMUM_FILE_LENGTH to confirm truncation before opening
  4. Enable fsync/durable storage checks if crashes repeatedly corrupt the cluster dir

Example fix

// before
NodeStateFile f = new NodeStateFile(clusterDir, false);
// after
if (new File(clusterDir, NodeStateFile.FILENAME).length() < NodeStateFile.MINIMUM_FILE_LENGTH) {
    new File(clusterDir, NodeStateFile.FILENAME).delete();
}
NodeStateFile f = new NodeStateFile(clusterDir, true);
Defensive patterns

Strategy: try-catch

Validate before calling

File f = new File(clusterDir, NodeStateFile.FILENAME); if (f.length() < NodeStateFile.MINIMUM_FILE_LENGTH) { /* restore backup or recreate */ }

Try / catch

try { f.loadInitialState(); } catch (IllegalStateException e) { /* restore from backup or recreate node-state file */ }

Prevention

When it happens

Trigger: Loading a node-state file that is truncated, partially written (e.g. crash mid-write), zero-length, or written by an incompatible writer that omitted the footer entry.

Common situations: Disk-full or power-loss during a node-state write; manually edited/truncated cluster files; restoring an incomplete backup of the cluster directory.

Related errors


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

Appendix: source

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

            buffer, 0, NodeStateHeaderDecoder.BLOCK_LENGTH, NodeStateHeaderDecoder.SCHEMA_VERSION);

        final int version = nodeStateHeaderDecoder.version();
        if (ClusterMarkFile.MAJOR_VERSION != SemanticVersion.major(version))
        {
            throw new ClusterException(
                "mark file major version " + SemanticVersion.major(version) +
                " does not match software: " + ClusterMarkFile.MAJOR_VERSION);
        }

        final int footerOffset = scanForMessageTypeOffset(
            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,

View on GitHub (pinned to 6d60124e15)