{"record":{"id":"bed3cdc3f7dcc702","repo":"aeron-io/aeron","slug":"message-length-0-file-corrupt","errorCode":null,"errorMessage":"Message length < 0, file corrupt?","messagePattern":"Message length < 0, file corrupt\\?","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/NodeStateFile.java","lineNumber":335,"sourceCode":"\n        while (position < buffer.capacity())\n        {\n            messageHeaderDecoder.wrap(buffer, position);\n\n            final int messageLength = messageHeaderDecoder.frameLength();\n\n            if (templateId == messageHeaderDecoder.templateId())\n            {\n                return position;\n            }\n            else if (NodeStateFooterEncoder.TEMPLATE_ID == messageHeaderDecoder.templateId())\n            {\n                return Aeron.NULL_VALUE;\n            }\n\n            if (messageLength < 0)\n            {\n                throw new IllegalStateException(\"Message length < 0, file corrupt?\");\n            }\n            else if (0 == messageLength)\n            {\n                return Aeron.NULL_VALUE;\n            }\n\n            position += align(messageLength, ALIGNMENT);\n        }\n\n        return Aeron.NULL_VALUE;\n    }\n\n    /**\n     * Wrapper class for the candidate term.\n     */\n    public final class CandidateTerm\n    {\n        private CandidateTerm()","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/NodeStateFile.java#L317-L353","documentation":"While scanning message records in the node state file, scanForMessageTypeOffset read a messageLength that is negative. Since message lengths are unsigned 32-bit SBE block lengths, a negative value means the file's framing is corrupted or the read pointer is misaligned. The library throws IllegalStateException rather than proceeding with a bogus length.","triggerScenarios":"Iterating messages via footerOffset() or candidateTermOffset() over a NodeStateFile whose bytes were truncated mid-record, overwritten, or written with a mismatched format; reading a file from disk while another process is still writing it.","commonSituations":"Disk full during a state write leaving a torn record; unclean shutdown without fsync; manual editing/copying of cluster data files; concurrent access to the state file from two processes.","solutions":["Treat the node state file as corrupt and restore it from a clean backup of the cluster data directory.","Rejoin the cluster / rebuild local state by re-fetching from the leader instead of replaying the damaged file.","Check for concurrent writers — ensure only one process opens the node state file.","Verify disk health and free space; confirm writes are properly flushed by the Aeron version in use."],"exampleFix":"// before\nfinal long offset = nodeStateFile.candidateTermOffset(); // throws if length < 0\n// after\ntry { final long offset = nodeStateFile.candidateTermOffset(); } catch (IllegalStateException e) { restoreStateFileFromBackup(); }","handlingStrategy":"try-catch","validationCode":"final long fileSize = file.length(); if (fileSize < MessageHeaderEncoder.ENCODED_LENGTH * 2) { treatAsCorrupt(file); }","typeGuard":null,"tryCatchPattern":"try { final long offset = nodeStateFile.candidateTermOffset(); } catch (IllegalStateException e) { markStateFileCorrupt(file); rebuildStateFromLeader(); }","preventionTips":["Ensure only one process opens the node state file at a time.","Monitor disk space/health on cluster members.","Restore from backup rather than attempting to repair torn records manually."],"tags":["cluster","corrupt-file","persistence","data-integrity"],"backgroundTag":"file-read-failed","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}