apache/cassandra · error · IllegalStateException
Cannot safely construct descriptor for segment, as name desc
Error message
Cannot safely construct descriptor for segment, as name descriptor implies a version that should contain a header descriptor, but that descriptor could not be read:
What it means
Thrown by maybeRestoreArchive() when a segment's filename implies a commit log descriptor version that must carry a header, but the header cannot be read (fromName != null but fromHeader == null). The file is truncated below the header size, unreadable, or its header is unrecoverable, so restore aborts.
Source
Thrown at src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java:293
for (String dir : restoreDirectories.split(DELIMITER))
{
File[] files = new File(dir).tryList();
if (files == null)
{
throw new RuntimeException("Unable to list directory " + dir);
}
for (File fromFile : files)
{
CommitLogDescriptor fromHeader = CommitLogDescriptor.fromHeader(fromFile, DatabaseDescriptor.getEncryptionContext());
CommitLogDescriptor fromName = CommitLogDescriptor.isValid(fromFile.name()) ? CommitLogDescriptor.fromFileName(fromFile.name()) : null;
CommitLogDescriptor descriptor;
if (fromHeader == null && fromName == null)
throw new IllegalStateException("Cannot safely construct descriptor for segment, either from its name or its header: " + fromFile.path());
else if (fromHeader != null && fromName != null && !fromHeader.equalsIgnoringCompression(fromName))
throw new IllegalStateException(String.format("Cannot safely construct descriptor for segment, as name and header descriptors do not match (%s vs %s): %s", fromHeader, fromName, fromFile.path()));
else if (fromName != null && fromHeader == null)
throw new IllegalStateException("Cannot safely construct descriptor for segment, as name descriptor implies a version that should contain a header descriptor, but that descriptor could not be read: " + fromFile.path());
else if (fromHeader != null)
descriptor = fromHeader;
else descriptor = fromName;
if (descriptor.version > CommitLogDescriptor.current_version)
throw new IllegalStateException("Unsupported commit log version: " + descriptor.version);
if (descriptor.compression != null)
{
try
{
CompressionParams.createCompressor(descriptor.compression);
}
catch (ConfigurationException e)
{
throw new IllegalStateException("Unknown compression", e);
}
}View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Re-copy the truncated segment from the archive and verify its size against the original.
- Delete 0-byte or partial files that are incomplete copies (the real segment remains in the archive).
- Check archive-side integrity (checksums) before restoring segments.
- Ensure the storage holding restore directories has no silent truncation (full disks, failed mounts).
Example fix
// before: partially copied segment (header missing) ls -l /mnt/restore/CommitLog-4-00000.log # 12 bytes // after: re-copy fully and verify size cp /archive/CommitLog-4-00000.log /mnt/restore/ && cmp /archive/CommitLog-4-00000.log /mnt/restore/CommitLog-4-00000.log
Defensive patterns
Strategy: validation
Validate before calling
for (File f : restoreDir.listFiles()) {
CommitLogDescriptor n = CommitLogDescriptor.isValid(f.getName()) ? CommitLogDescriptor.fromFileName(f.getName()) : null;
if (n != null && CommitLogDescriptor.fromHeader(f, DatabaseDescriptor.getEncryptionContext()) == null)
log.warn("Segment too small/truncated to read header, re-copy: " + f);
} Try / catch
try { archiver.maybeRestoreArchive(); }
catch (IllegalStateException e) {
if (e.getMessage().contains("header descriptor could not be read"))
log.error("Segment truncated/incomplete; re-copy full segment from archive", e);
throw e;
} Prevention
- Verify copied segment sizes/checksums against the archive before startup
- Guard archive copies against interruption (use atomic rename after full copy)
- Delete 0-byte partial files left by failed transfers
When it happens
Trigger: A restore-directory file has a valid modern-format name but CommitLogDescriptor.fromHeader returns null because the file is truncated (smaller than the descriptor header), empty, or the header bytes are unreadable/corrupt.
Common situations: Interrupted copy of an archived segment (partial file); 0-byte placeholder files; disk corruption at the start of the segment; rsync/scp interrupted mid-transfer.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Cannot safely construct descriptor for segment, either from
- Unable to list directory
- Cannot safely construct descriptor for segment, as name and
- Missing required directive CommitLogSync
- Batch sync specified, but commitlog_sync_period found.
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/d965ed688e5e7102.
Report an issue: GitHub.