{"record":{"id":"079548e51aeb1ee3","repo":"apache/cassandra","slug":"a-ttl-should-not-be-negative-079548","errorCode":null,"errorMessage":"A TTL should not be negative","messagePattern":"A TTL should not be negative","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/db/rows/AbstractCell.java","lineNumber":189,"sourceCode":"\n    public void digest(Digest digest)\n    {\n        if (isCounterCell())\n            digest.updateWithCounterContext(value(), accessor());\n        else\n            digest.update(value(), accessor());\n\n        digest.updateWithLong(timestamp())\n              .updateWithInt(ttl())\n              .updateWithBoolean(isCounterCell());\n        if (path() != null)\n            path().digest(digest);\n    }\n\n    public void validate()\n    {\n        if (ttl() < 0)\n            throw new MarshalException(\"A TTL should not be negative\");\n        if (localDeletionTime() < 0)\n            throw new MarshalException(\"A local deletion time should not be negative\");\n        if (localDeletionTime() == INVALID_DELETION_TIME)\n            throw new MarshalException(\"A local deletion time should not be a legacy overflowed value\");\n        if (isExpiring() && localDeletionTime() == NO_DELETION_TIME)\n            throw new MarshalException(\"Shoud not have a TTL without an associated local deletion time\");\n\n        // non-frozen UDTs require both the cell path & value to validate,\n        // so that logic is pushed down into ColumnMetadata. Tombstone\n        // validation is done there too as it also involves the cell path\n        // for complex columns\n        column().validateCell(this);\n    }\n\n    public boolean hasInvalidDeletions()\n    {\n        if (ttl() < 0 || localDeletionTime() == INVALID_DELETION_TIME || localDeletionTime() < 0 || (isExpiring() && localDeletionTime() == NO_DELETION_TIME))\n            return true;","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/rows/AbstractCell.java#L171-L207","documentation":"AbstractCell.validate() checks a cell's invariants when it is written or read back. A negative TTL can never be produced by a correct writer, so a negative value means corrupted data on disk, a bad serialization, or a bug in a custom cell implementation. The cell is rejected with a MarshalException rather than propagating invalid data.","triggerScenarios":"Reading a cell whose serialized TTL field was corrupted or written by a buggy encoder; deserializing hand-crafted/mutated SSTable or mutation data; a custom IVersionedAsymmetricSerializer or cell factory that passes negative ttl values.","commonSituations":"Corrupt SSTables after hardware failure; third-party tools writing sstables directly; fuzzing/ingestion of malformed commitlog segments; downgrade/upgrade paths with format bugs.","solutions":["Run `nodetool scrub` on the affected table to drop corrupt cells.","Restore the affected data from backups/snapshots.","Check disk/filesystem health (smartctl, fsck) for silent corruption.","File/inspect the writer path: verify no custom code produces negative TTLs."],"exampleFix":"// before: writing with unvalidated ttl\nlong ttl = computeTtl(request);\ncell = cf.cell(column, ts, (int) ttl, ldt, value);\n// after\nint ttl = computeTtl(request);\nif (ttl < 0) throw new IllegalArgumentException(\"TTL must be >= 0\");","handlingStrategy":"validation","validationCode":"if (cell.ttl() < 0) throw new IllegalArgumentException(\"negative TTL before write\");","typeGuard":"boolean hasValidTtl(AbstractCell<?> c) { return c.ttl() >= 0; }","tryCatchPattern":"try { row.validate(); } catch (MarshalException e) { quarantineCorruptRow(rowKey); scrubTable(); }","preventionTips":["Always validate rows before persisting via custom writers","Scrub after any disk failure or restore","Keep TTL computation clamped to >= 0"],"tags":["validation","data-corruption","ttl","marshal"],"backgroundTag":"value-out-of-range","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"}