{"record":{"id":"d3d0d6083abfd2c6","repo":"apache/cassandra","slug":"a-ttl-should-not-be-negative","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/LivenessInfo.java","lineNumber":334,"sourceCode":"        }\n\n        @Override\n        public void digest(Digest digest)\n        {\n            super.digest(digest);\n\n            // As of 5.0, local expiration times are encoded as unsigned integers on disk, so we can do the\n            // same thing here to populate the digest. This supports extended TTLs, but also maintains digest\n            // compatibility with previous versions, avoiding false digest mismatches during upgrades.\n            digest.updateWithInt(Cell.deletionTimeLongToUnsignedInteger(localExpirationTime));\n            digest.updateWithInt(ttl);\n        }\n\n        @Override\n        public void validate()\n        {\n            if (ttl < 0)\n                throw new MarshalException(\"A TTL should not be negative\");\n            if (localExpirationTime < 0)\n                throw new MarshalException(\"A local expiration time should not be negative\");\n        }\n\n        @Override\n        public int dataSize()\n        {\n            return super.dataSize()\n                 + TypeSizes.sizeof(ttl)\n                 + TypeSizes.sizeof(localExpirationTime);\n\n        }\n\n        @Override\n        public LivenessInfo withUpdatedTimestamp(long newTimestamp)\n        {\n            return new ExpiringLivenessInfo(newTimestamp, ttl, localExpirationTime);\n        }","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/LivenessInfo.java#L316-L352","documentation":"ExpiringLivenessInfo (LivenessInfo.Expiring) validates its fields on construction/deserialization: a negative TTL is illegal because TTLs are non-negative durations in seconds. MarshalException is thrown to reject corrupt or invalid expiration data before it enters the read/write path.","triggerScenarios":"Writing a cell with a negative TTL (e.g. INSERT ... USING TTL -1); deserializing corrupt SSTable or mutation data where the TTL field is negative; passing a computed TTL expression that underflows to negative.","commonSituations":"Application computes TTL from a timestamp difference that came out negative (clock skew or expired deadline); drivers accepting client-supplied TTL values without validation; corrupted data files.","solutions":["Clamp or validate TTL before writing: reject or floor negative computed values to 0 (no expiration).","Fix the source arithmetic (e.g. deadline - now) and guard against clock skew.","If it appears during reads without negative writes, run a repair/scrub — the data may be corrupt."],"exampleFix":"// before\nint ttl = (int) ((expiryAt - System.currentTimeMillis()) / 1000); // can be negative\nsession.execute(\"INSERT INTO t(k,v) VALUES(?,?,?) USING TTL ?\", k, v, ttl);\n// after\nint ttl = Math.max(0, (int) ((expiryAt - System.currentTimeMillis()) / 1000));\nsession.execute(\"INSERT INTO t(k,v) VALUES(?,?,?) USING TTL ?\", k, v, ttl);","handlingStrategy":"validation","validationCode":"if (ttl < 0) throw new IllegalArgumentException(\"TTL must be >= 0, got \" + ttl);","typeGuard":"int safeTtl(long computedTtl) { return (int) Math.max(0, computedTtl); }","tryCatchPattern":"try { session.execute(stmt); } catch (InvalidQueryException e) { if (e.getMessage().contains(\"TTL\")) { fixTtlAndRetry(); } else throw e; }","preventionTips":["Clamp computed TTLs with Math.max(0, ttl) before binding.","Validate user-supplied TTLs at the API boundary.","Account for clock skew when deriving TTL from timestamps."],"tags":["ttl","marshal","validation","value-out-of-range"],"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"}