apache/cassandra · error · InvalidRequestException

Invalid TTL value: <tval>

Error message

Invalid TTL value: <tval>

What it means

Attributes.getTimeToLive resolves the USING TTL term; the bound value must be a valid Int32Type-encoded 4-byte int. If Int32Type.instance.validate throws MarshalException, the method throws InvalidRequestException 'Invalid TTL value: <bytes>'. This is a format validation of the bound TTL bytes, separate from range checks.

Source

Thrown at src/java/org/apache/cassandra/cql3/Attributes.java:135

        ByteBuffer tval = timeToLive.bindAndGet(context);
        if (tval == null)
            return 0;

        if (tval == ByteBufferUtil.UNSET_BYTE_BUFFER)
            return metadata.params.defaultTimeToLive;

        // byte[0] and null are the same for Int32Type.  UNSET_BYTE_BUFFER is also byte[0] but we rely on pointer
        // identity, so need to check this after checking that
        if (ByteBufferUtil.EMPTY_BYTE_BUFFER.equals(tval))
            return 0;

        try
        {
            Int32Type.instance.validate(tval);
        }
        catch (MarshalException e)
        {
            throw new InvalidRequestException("Invalid TTL value: " + tval);
        }

        int ttl = Int32Type.instance.compose(tval);
        if (ttl < 0)
            throw new InvalidRequestException("A TTL must be greater or equal to 0, but was " + ttl);

        if (ttl > MAX_TTL)
            throw new InvalidRequestException(String.format("ttl is too large. requested (%d) maximum (%d)", ttl, MAX_TTL));

        if (metadata.params.defaultTimeToLive != LivenessInfo.NO_TTL && ttl == LivenessInfo.NO_TTL)
            return LivenessInfo.NO_TTL;

        ExpirationDateOverflowHandling.maybeApplyExpirationDateOverflowPolicy(metadata, ttl, false);

        return ttl;
    }

    public void collectMarkerSpecification(VariableSpecifications boundNames)

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Bind the TTL as a Java int through the driver instead of raw buffers
  2. Encode with Int32Type.instance.decompose(ttl) in custom code
  3. Ensure the value fits in 32-bit signed int and is 4 bytes big-endian
  4. Re-check the driver/API used to bind USING TTL values

Example fix

// before
ByteBuffer ttlBytes = ByteBuffer.allocate(8).putLong(3600L); // 8 bytes
// after
ByteBuffer ttlBytes = Int32Type.instance.decompose(3600); // valid int32
Defensive patterns

Strategy: validation

Validate before calling

void validateTtlBytes(ByteBuffer tval) {
    try { org.apache.cassandra.db.marshal.Int32Type.instance.validate(tval); }
    catch (org.apache.cassandra.serializers.MarshalException e) {
        throw new IllegalArgumentException("ttl must be an int32-encoded buffer", e);
    }
}

Type guard

boolean isIntEncoded(ByteBuffer b) { return b != null && b.remaining() == 4; }

Try / catch

try {
    session.execute(bs);
} catch (InvalidQueryException e) {
    if (e.getMessage().startsWith("Invalid TTL value"))
        log.error("Bind USING TTL as int via driver typed setters");
    throw e;
}

Prevention

When it happens

Trigger: 'USING TTL ?' bound with byte values that are not a valid int32 serialization (wrong length, string bytes, oversized long) through raw term binding paths.

Common situations: Custom query handlers or thrift-era code assembling bound values manually; binding a long TTL into an int slot with a full 8-byte buffer; drivers sending text-encoded numbers.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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