apache/cassandra · error · MarshalException

A TTL should not be negative

Error message

A TTL should not be negative

What it means

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.

Source

Thrown at src/java/org/apache/cassandra/db/LivenessInfo.java:334

        }

        @Override
        public void digest(Digest digest)
        {
            super.digest(digest);

            // As of 5.0, local expiration times are encoded as unsigned integers on disk, so we can do the
            // same thing here to populate the digest. This supports extended TTLs, but also maintains digest
            // compatibility with previous versions, avoiding false digest mismatches during upgrades.
            digest.updateWithInt(Cell.deletionTimeLongToUnsignedInteger(localExpirationTime));
            digest.updateWithInt(ttl);
        }

        @Override
        public void validate()
        {
            if (ttl < 0)
                throw new MarshalException("A TTL should not be negative");
            if (localExpirationTime < 0)
                throw new MarshalException("A local expiration time should not be negative");
        }

        @Override
        public int dataSize()
        {
            return super.dataSize()
                 + TypeSizes.sizeof(ttl)
                 + TypeSizes.sizeof(localExpirationTime);

        }

        @Override
        public LivenessInfo withUpdatedTimestamp(long newTimestamp)
        {
            return new ExpiringLivenessInfo(newTimestamp, ttl, localExpirationTime);
        }

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Clamp or validate TTL before writing: reject or floor negative computed values to 0 (no expiration).
  2. Fix the source arithmetic (e.g. deadline - now) and guard against clock skew.
  3. If it appears during reads without negative writes, run a repair/scrub — the data may be corrupt.

Example fix

// before
int ttl = (int) ((expiryAt - System.currentTimeMillis()) / 1000); // can be negative
session.execute("INSERT INTO t(k,v) VALUES(?,?,?) USING TTL ?", k, v, ttl);
// after
int ttl = Math.max(0, (int) ((expiryAt - System.currentTimeMillis()) / 1000));
session.execute("INSERT INTO t(k,v) VALUES(?,?,?) USING TTL ?", k, v, ttl);
Defensive patterns

Strategy: validation

Validate before calling

if (ttl < 0) throw new IllegalArgumentException("TTL must be >= 0, got " + ttl);

Type guard

int safeTtl(long computedTtl) { return (int) Math.max(0, computedTtl); }

Try / catch

try { session.execute(stmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("TTL")) { fixTtlAndRetry(); } else throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/d3d0d6083abfd2c6. Report an issue: GitHub.