apache/cassandra · warning
Found a legacy log record
Error message
Found a legacy log record {} with updateTime based on the stats file, ignoring to allow startup to continue What it means
LogFile.verifyRecord detects an sstable lifecycle log record whose update time matches the old buggy behavior where the timestamp was derived from the stats file instead of the data files. To let nodes upgraded from such a broken version start up, Cassandra logs this warning and skips the error that would otherwise be raised for 'unexpected files detected'.
Solutions
- No action required — Cassandra intentionally ignores the legacy record to allow startup.
- After a successful upgrade, verify the affected sstables with nodetool verify/scrub.
- Run a full compaction or major repair to rewrite sstables and regenerate clean transaction logs.
Defensive patterns
Strategy: fallback
Prevention
- Upgrade through supported version paths so legacy record handling applies.
- After upgrade, run nodetool scrub/verify to rewrite legacy artifacts.
- Keep txn log directories on reliable storage.
When it happens
Trigger: Startup (or txn log verification) encounters a legacy transaction record written by a patched/older Cassandra version where LogRecord.make with statsIncluded=true reproduces the same truncated update time; i.e. first upgrade from a version that based updateTime on the stats file.
Common situations: Upgrading an old cluster (pre-fix transaction log validation) to a modern version with strict record verification; broken transaction files left on disk from the older release.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Found unknown system directory
- Last record of transaction
- 3
- A local deletion time should not be a legacy overflowed…
- accord.journal_directory must not be the same as the…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/0a7ee59c630077b7.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/lifecycle/LogFile.java:287
return;
// Paranoid sanity checks: we create another record by looking at the files as they are
// on disk right now and make sure the information still matches. We don't want to delete
// files by mistake if the user has copied them from backup and forgot to remove a txn log
// file that obsoleted the very same files. So we check the latest update time and make sure
// it matches. Because we delete files from oldest to newest, the latest update time should
// always match.
record.status.onDiskRecord = record.withExistingFiles(existingFiles);
// we can have transaction files with mismatching updateTime resolutions due to switching between jdk8 and jdk11, truncate both to be consistent:
if (truncateMillis(record.updateTime) != truncateMillis(record.status.onDiskRecord.updateTime) && record.status.onDiskRecord.updateTime > 0)
{
// handle the case where we have existing broken transaction file on disk, where the update time is
// based on the stats file. This is just for the first upgrade, patched versions never base the update
// time on the stats file.
LogRecord statsIncluded = LogRecord.make(record.type, existingFiles, existingFiles.size(), record.absolutePath(), true);
if (truncateMillis(statsIncluded.updateTime) == truncateMillis(record.updateTime))
{
logger.warn("Found a legacy log record {} with updateTime based on the stats file, ignoring to allow startup to continue", record);
return;
}
record.setError(String.format("Unexpected files detected for sstable [%s]: " +
"last update time [%tc] (%d) should have been [%tc] (%d)",
record.fileName(),
record.status.onDiskRecord.updateTime,
record.status.onDiskRecord.updateTime,
record.updateTime,
record.updateTime));
}
}
/**
* due to difference in timestamp resolution between jdk8 and 11 we need to return second resolution here (number
* should end in 000): https://bugs.openjdk.java.net/browse/JDK-8177809
*/
static long truncateMillis(long lastModified)View on GitHub (pinned to 88fd0f6a0e)