{"record":{"id":"fea1375a2135a8a6","repo":"apache/cassandra","slug":"commit-log-header-has-not-been-written","errorCode":null,"errorMessage":"commit log header has not been written","messagePattern":"commit log header has not been written","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java","lineNumber":308,"sourceCode":"\n    /**\n     * Wait for any appends or discardUnusedTail() operations started before this method was called\n     */\n    void waitForModifications()\n    {\n        // issue a barrier and wait for it\n        appendOrder.awaitNewBarrier();\n    }\n\n    /**\n     * Update the chained markers in the commit log buffer and possibly force a disk flush for this segment file.\n     *\n     * @param flush true if the segment should flush to disk; else, false for just updating the chained markers.\n     */\n    synchronized void sync(boolean flush)\n    {\n        if (!headerWritten)\n            throw new IllegalStateException(\"commit log header has not been written\");\n        assert lastMarkerOffset >= lastSyncedOffset : String.format(\"commit log segment positions are incorrect: last marked = %d, last synced = %d\",\n                                                                    lastMarkerOffset, lastSyncedOffset);\n        // check we have more work to do\n        final boolean needToMarkData = allocatePosition.get() > lastMarkerOffset + SYNC_MARKER_SIZE;\n        final boolean hasDataToFlush = lastSyncedOffset != lastMarkerOffset;\n        if (!(needToMarkData || hasDataToFlush))\n            return;\n        // Note: Even if the very first allocation of this sync section failed, we still want to enter this\n        // to ensure the segment is closed. As allocatePosition is set to 1 beyond the capacity of the buffer,\n        // this will always be entered when a mutation allocation has been attempted after the marker allocation\n        // succeeded in the previous sync.\n        assert buffer != null;  // Only close once.\n\n        boolean close = false;\n        int startMarker = lastMarkerOffset;\n        int nextMarker, sectionEnd;\n        if (needToMarkData)\n        {","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java#L290-L326","documentation":"CommitLogSegment.sync(flush) is an internal invariant: a segment must have had its CDC/commit log header written before any sync (including the close() path) can run. Throwing IllegalStateException(\"commit log header has not been written\") signals that sync was invoked on a segment whose header allocation never completed — a bug in segment lifecycle rather than user input.","triggerScenarios":"Calling sync() or close() on a CommitLogSegment before writeLogHeader has run (headerWritten == false), e.g. creating/discarding a segment abnormally during startup, tests manipulating segments directly, or a failure between segment creation and header write.","commonSituations":"Custom tooling or tests constructing CommitLogSegment instances and syncing/closing them directly; crashes during commit log segment initialization; bugs in custom CommitLogSegmentManager extensions.","solutions":["Ensure the segment's header is written (allocatePosition / writeLogHeader path completes) before calling sync or close.","Discard unused segments via the segment manager's discard path instead of closing them directly.","Upgrade Cassandra: lifecycle bugs around header writing have been fixed in later releases.","If seen in production without custom code, capture the stack and file a JIRA — it indicates an internal race."],"exampleFix":"// before (test code)\nsegment.sync(true);\n// after\nsegment.writeLogHeader(commitLog.configuration().getCRCIgnoreChance());\nsegment.sync(true);","handlingStrategy":"try-catch","validationCode":"if (!segment.isHeaderWritten())\n    throw new IllegalStateException(\"Sync attempted before header write\");","typeGuard":null,"tryCatchPattern":"try {\n    segment.sync(true);\n} catch (IllegalStateException e) {\n    logger.error(\"Commit log segment lifecycle bug: {}\", e.getMessage());\n}","preventionTips":["Never call sync/close directly on raw CommitLogSegment instances in tests or tools","Use the segment manager's allocate/discard APIs for lifecycle","Keep Cassandra upgraded — header-write races are fixed over time"],"tags":["commitlog","internal","lifecycle","sync"],"backgroundTag":"internal-invariant-violation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}