apache/cassandra · error · InvalidRequestException

Invalid null value for counter increment

Error message

Invalid null value for counter increment

What it means

Thrown at execution time when a counter increment (Stats.Setter/increment path) binds to null. Like the literal case, counters have no null value: the delta must be a concrete long, so a null bind marker result is rejected.

Solutions

  1. Bind a non-null long, defaulting to 0 when no delta applies
  2. Omit the counter update (or the whole statement) when the delta is unknown
  3. Use ByteBufferUtil.UNSET semantics via the driver's unset value if the column should be skipped, not null

Example fix

// before
ps.bind(0, delta); // delta may be null
// after
ps.bind(0, delta == null ? 0L : delta);
Defensive patterns

Strategy: validation

Validate before calling

Objects.requireNonNull(delta, "counter increment must not be null");

Try / catch

try { session.execute(ps.bind(delta)); } catch (InvalidQueryException e) { if (e.getMessage().contains("Invalid null value for counter increment")) { /* default to 0 or skip */ } else throw e; }

Prevention

When it happens

Trigger: `UPDATE t SET c = c + ?` executed with the parameter bound to null (driver `unset` vs null distinction: null is rejected, unset is skipped).

Common situations: Nullable counter-delta fields in application DTOs; batch builders that add statements with null values by default; missing request data in APIs that map straight to CQL binds.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/terms/Constants.java:520

    public static class Adder extends Operation
    {
        public Adder(ColumnMetadata column, Term t)
        {
            super(column, t);
        }

        public boolean requiresRead()
        {
            return !(column.type instanceof CounterColumnType);
        }

        public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
        {
            if (column.type instanceof CounterColumnType)
            {
                ByteBuffer bytes = t.bindAndGet(builder);
                if (bytes == null)
                    throw new InvalidRequestException("Invalid null value for counter increment");
                if (bytes == ByteBufferUtil.UNSET_BYTE_BUFFER)
                    return;

                long increment = ByteBufferUtil.toLong(bytes);
                builder.addCounter(column, increment);
            }
            else if (column.type instanceof NumberType<?>)
            {
                @SuppressWarnings("unchecked") NumberType<Number> type = (NumberType<Number>) column.type;
                ByteBuffer increment = type.sanitize(t.bindAndGet(builder));
                if (increment == null)
                    return;
                ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, builder));
                if (current == null)
                    return;
                ByteBuffer newValue = type.add(type.compose(current), type.compose(increment));
                builder.addCell(column, newValue);
            }

View on GitHub (pinned to 88fd0f6a0e)