apache/cassandra · error · InvalidRequestException

Cannot replace aggregate

Error message

Cannot replace aggregate '%s', the new return type %s isn't compatible with the return type %s of existing function

What it means

Thrown when OR REPLACE is used to replace an existing aggregate but the new aggregate's return type is not compatible with the existing one's return type. Cassandra prevents replacing an aggregate in a way that changes its output type incompatibly.

Solutions

  1. Keep the new return type compatible with the existing one (choose a final function whose return type is compatible).
  2. DROP AGGREGATE the old aggregate, then CREATE the new one with the desired return type.
  3. Update all dependent queries/views that rely on the old return type before replacing.

Example fix

// before
CREATE AGGREGATE OR REPLACE ks.avg(int) SFUNC s STYPE int FINALFUNC to_int; -- was double-returning
// after
DROP AGGREGATE ks.avg(int);
CREATE AGGREGATE ks.avg(int) SFUNC s STYPE int FINALFUNC to_int;
Defensive patterns

Strategy: validation

Validate before calling

var existing = keyspace.userFunctions.find(fnName, argTypes);
if (existing.isPresent() && existing.get().isAggregate() && useOrReplace
    && !newReturnType.isCompatibleWith(existing.get().returnType()))
    throw new IllegalStateException("Return type " + newReturnType + " incompatible with existing " + existing.get().returnType());

Try / catch

try { session.execute(ddl); }
catch (InvalidRequestException e) {
    if (e.getMessage().contains("isn't compatible")) { /* DROP AGGREGATE then recreate */ }
    else throw e;
}

Prevention

When it happens

Trigger: CREATE AGGREGATE OR REPLACE where the final function (or state function) yields a return type that fails AbstractType.isCompatibleWith against the existing aggregate's return type — e.g. replacing a double-returning aggregate with an int-returning one.

Common situations: Changing FINALFUNC to one with a different return type while reusing OR REPLACE; widening/narrowing state type during schema evolution.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateAggregateStatement.java:233

                            (ScalarFunction) stateFunction,
                            (ScalarFunction) finalFunction,
                            initialValue);

        UserFunction existingAggregate = keyspace.userFunctions.find(aggregate.name(), argumentTypes).orElse(null);
        if (null != existingAggregate)
        {
            if (!existingAggregate.isAggregate())
                throw ire("Aggregate '%s' cannot replace a function", aggregateName);

            if (ifNotExists)
                return schema;

            if (!orReplace)
                throw ire("Aggregate '%s' already exists", aggregateName);

            if (!returnType.isCompatibleWith(existingAggregate.returnType()))
            {
                throw ire("Cannot replace aggregate '%s', the new return type %s isn't compatible with the return type %s of existing function",
                          aggregateName,
                          returnType.asCQL3Type(),
                          existingAggregate.returnType().asCQL3Type());
            }
        }

        return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.userFunctions.withAddedOrUpdated(aggregate)));
    }

    private static boolean isNullOrEmpty(AbstractType<?> type, ByteBuffer bb)
    {
        return bb == null ||
               (bb.remaining() == 0 && type.isEmptyValueMeaningless());
    }

    SchemaChange schemaChangeEvent(KeyspacesDiff diff)
    {
        assert diff.altered.size() == 1;

View on GitHub (pinned to 88fd0f6a0e)