{"record":{"id":"b3a5f9ebcaa5956a","repo":"aeron-io/aeron","slug":"invalid-nextrecordingid-expected-value-greater-or-equal-to","errorCode":null,"errorMessage":"invalid nextRecordingId: expected value greater or equal to \" + (recordingId + 1) + \", was \" + nextRecordingId","messagePattern":"invalid nextRecordingId: expected value greater or equal to \" \\+ \\(recordingId \\+ 1\\) \\+ \", was \" \\+ nextRecordingId","errorType":"exception","errorClass":"ArchiveException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/Catalog.java","lineNumber":976,"sourceCode":"\n            recordingId = recordingId(catalogBuffer);\n            if (isValidDescriptor(catalogBuffer))\n            {\n                catalogIndex.add(recordingId, offset);\n            }\n\n            offset += frameLength;\n        }\n\n        nextRecordingDescriptorOffset = offset;\n\n        if (0 == nextRecordingId)\n        {\n            nextRecordingId = recordingId + 1;\n        }\n        else if (writable && nextRecordingId < recordingId + 1)\n        {\n            throw new ArchiveException(\"invalid nextRecordingId: expected value greater or equal to \" +\n                (recordingId + 1) + \", was \" + nextRecordingId);\n        }\n    }\n\n    private void invokeEntryProcessor(final int recordingDescriptorOffset, final CatalogEntryProcessor consumer)\n    {\n        descriptorHeaderDecoder.wrap(\n            catalogBuffer, 0, DESCRIPTOR_HEADER_LENGTH, RecordingDescriptorHeaderDecoder.SCHEMA_VERSION);\n\n        descriptorHeaderEncoder.wrap(catalogBuffer, 0);\n\n        descriptorDecoder.wrap(\n            catalogBuffer,\n            DESCRIPTOR_HEADER_LENGTH,\n            RecordingDescriptorDecoder.BLOCK_LENGTH,\n            RecordingDescriptorDecoder.SCHEMA_VERSION);\n\n        descriptorEncoder.wrap(catalogBuffer, DESCRIPTOR_HEADER_LENGTH);","sourceCodeStart":958,"sourceCodeEnd":994,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/Catalog.java#L958-L994","documentation":"Thrown when the catalog's nextRecordingId field, persisted in the catalog file, is lower than recordingId + 1 for an existing entry — i.e. the catalog's high-water-mark of recording IDs is inconsistent with an entry it contains. This guards against corrupted or hand-edited catalog files where the next ID counter was reset while entries still exist, which would cause new recordings to reuse existing IDs. Only thrown when the catalog is writable.","triggerScenarios":"Opening a writable Catalog whose header nextRecordingId is 0-positive but < max(recordingId)+1, typically after a corrupted catalog, a partial write/crash during catalog update, manual truncation, or copying an older catalog file over a newer one.","commonSituations":"Disk corruption or crash without clean shutdown truncating catalog updates; restoring catalog from backup taken before newer recordings were made; mixing catalog files across archive instances; ArchiveTool usage that mutated entries without updating the header counter.","solutions":["Restore a consistent catalog: run ArchiveTool verify/recover against the archive directory to rebuild or repair the catalog","Restore the correct catalog file from a backup that includes all recorded entries","Repair nextRecordingId to recordingId + 1 using CatalogTool or ArchiveTool repair options if you accept the risk after verifying entries","Open the catalog read-only (writable=false) if you only need to inspect recordings, which bypasses this check"],"exampleFix":"// before\ncp backup/catalog catalog // older catalog overwritten newer one\n// after\njava -cp aeron-samples.jar io.aeron.archive.tool.ArchiveTool verify /archive/dir\n# then restore catalog from a backup taken after the last recording, or repair nextRecordingId","handlingStrategy":"try-catch","validationCode":"// Before opening writable, sanity check the catalog header via CatalogTool:\n// java -cp aeron-samples.jar io.aeron.archive.tool.CatalogTool describe <archive-dir>","typeGuard":null,"tryCatchPattern":"try (Catalog catalog = new Catalog(archiveDir, clock, fileSyncLevel, writable=true, capacity, null, null)) {\n    // use catalog\n} catch (ArchiveException e) {\n    if (e.getMessage().startsWith(\"invalid nextRecordingId\")) {\n        // catalog header inconsistent with entries: run ArchiveTool verify / restore backup\n    } else {\n        throw e;\n    }\n}","preventionTips":["Shut down the archive and media driver gracefully; avoid kill -9 during recording","Never manually edit or truncate catalog files","Take catalog backups only after clean shutdowns","Run ArchiveTool verify after any crash before restarting the archive"],"tags":["aeron-archive","catalog-corruption","state-consistency"],"backgroundTag":"internal-invariant-violation","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"}