{"record":{"id":"53b7c49d31cb01cf","repo":"apache/cassandra","slug":"a-ttl-must-be-greater-or-equal-to-0-but-was-ttl","errorCode":null,"errorMessage":"A TTL must be greater or equal to 0, but was <ttl>","messagePattern":"A TTL must be greater or equal to 0, but was <ttl>","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/Attributes.java","lineNumber":140,"sourceCode":"            return metadata.params.defaultTimeToLive;\n\n        // byte[0] and null are the same for Int32Type.  UNSET_BYTE_BUFFER is also byte[0] but we rely on pointer\n        // identity, so need to check this after checking that\n        if (ByteBufferUtil.EMPTY_BYTE_BUFFER.equals(tval))\n            return 0;\n\n        try\n        {\n            Int32Type.instance.validate(tval);\n        }\n        catch (MarshalException e)\n        {\n            throw new InvalidRequestException(\"Invalid TTL value: \" + tval);\n        }\n\n        int ttl = Int32Type.instance.compose(tval);\n        if (ttl < 0)\n            throw new InvalidRequestException(\"A TTL must be greater or equal to 0, but was \" + ttl);\n\n        if (ttl > MAX_TTL)\n            throw new InvalidRequestException(String.format(\"ttl is too large. requested (%d) maximum (%d)\", ttl, MAX_TTL));\n\n        if (metadata.params.defaultTimeToLive != LivenessInfo.NO_TTL && ttl == LivenessInfo.NO_TTL)\n            return LivenessInfo.NO_TTL;\n\n        ExpirationDateOverflowHandling.maybeApplyExpirationDateOverflowPolicy(metadata, ttl, false);\n\n        return ttl;\n    }\n\n    public void collectMarkerSpecification(VariableSpecifications boundNames)\n    {\n        if (timestamp != null)\n            timestamp.collectMarkerSpecification(boundNames, this);\n        if (timeToLive != null)\n            timeToLive.collectMarkerSpecification(boundNames, this);","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/Attributes.java#L122-L158","documentation":"A bound TTL that decodes to a negative int is rejected: TTL semantics require 0 (no expiry) or a positive number of seconds. Attributes.getTimeToLive throws InvalidRequestException 'A TTL must be greater or equal to 0, but was <ttl>'.","triggerScenarios":"'USING TTL ?' bound with a negative int value (e.g. -1) coming from client code, computed values, or overflow of arithmetic on the client side.","commonSituations":"Passing -1 as a sentinel for 'no TTL' (the correct sentinel is 0); subtraction/date math producing negative durations; configuration default TTL values entered as negative numbers.","solutions":["Clamp or validate the TTL client-side: if (ttl < 0) ttl = 0; or reject before executing","Use 0 to mean 'no TTL' instead of negative sentinels","Fix the calculation producing the negative duration (e.g. expiry - now when expiry already passed)","Re-run the statement with a non-negative TTL"],"exampleFix":"// before\nint ttl = (int) Duration.between(now, expiry).getSeconds(); // may be negative\n// after\nint ttl = Math.max(0, (int) Duration.between(now, expiry).getSeconds());","handlingStrategy":"validation","validationCode":"int safeTtl(int requested) {\n    if (requested < 0)\n        throw new IllegalArgumentException(\"TTL must be >= 0; use 0 for no expiry\");\n    return requested;\n}","typeGuard":"boolean isValidTtl(Integer ttl) { return ttl != null && ttl >= 0; }","tryCatchPattern":"try {\n    session.execute(bs);\n} catch (InvalidQueryException e) {\n    if (e.getMessage().startsWith(\"A TTL must be greater or equal to 0\"))\n        log.error(\"Negative TTL bound; use 0 for no-expiry, not negative sentinels\");\n    throw e;\n}","preventionTips":["Use 0 as the 'no TTL' sentinel, never negative values","Clamp computed durations with Math.max(0, ttl)","Validate user-supplied TTLs at the API boundary","Beware of arithmetic underflow when deriving TTLs from dates"],"tags":["cql","ttl","invalid-request"],"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-14T11:17:12.474Z"}