apache/cassandra · error · InvalidRequestException

State function isn't a scalar function

Error message

State function %s isn't a scalar function

What it means

The state function resolved for the aggregate is itself an aggregate, not a scalar (non-aggregate) function. An aggregate's state function must be a plain user function; nesting aggregates is not allowed.

Solutions

  1. Point SFUNC at a scalar function with a matching signature (CREATE FUNCTION if missing)
  2. Drop/rename the conflicting aggregate so the name resolves to the scalar function
  3. Qualify with a different keyspace where the name refers to a scalar function

Example fix

// before
CREATE FUNCTION ks.avg AS ... ; CREATE AGGREGATE ks.total(int) SFUNC avg ...
// after
CREATE FUNCTION ks.avg_state(int,int) ...
CREATE AGGREGATE ks.total(int) SFUNC avg_state ...
Defensive patterns

Strategy: validation

Validate before calling

// verify the SFUNC resolves to a scalar function before CREATE AGGREGATE
Row f = session.execute("SELECT argument_types, return_type FROM system_schema.functions WHERE keyspace_name=? AND function_name=?", ks, sfunc).one();
if (f == null) throw new IllegalStateException("SFUNC not found: " + sfunc);

Try / catch

try { session.execute(ddl); }
catch (InvalidRequestException e) { if (e.getMessage().contains("isn't a scalar function")) pickScalarFunctionFor(sfuncName); else throw e; }

Prevention

When it happens

Trigger: keyspace.userFunctions.find(stateFunctionName, stateFunctionArguments) returns a UserFunction whose isAggregate() is true, in CreateAggregateStatement.apply.

Common situations: Using an existing aggregate name as the SFUNC of a new aggregate; accidentally creating a function with the same signature as an aggregate earlier.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

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

        /*
         * Resolve the state function
         */

        List<AbstractType<?>> argumentTypes =
            rawArgumentTypes.stream()
                            .map(t -> t.prepare(keyspaceName, keyspace.types).getType().udfType())
                            .collect(toList());
        AbstractType<?> stateType = rawStateType.prepare(keyspaceName, keyspace.types).getType().udfType();
        List<AbstractType<?>> stateFunctionArguments = Lists.newArrayList(concat(singleton(stateType), argumentTypes));

        UserFunction stateFunction =
            keyspace.userFunctions
                    .find(stateFunctionName, stateFunctionArguments)
                    .orElseThrow(() -> ire("State function %s doesn't exist", stateFunctionString()));

        if (stateFunction.isAggregate())
            throw ire("State function %s isn't a scalar function", stateFunctionString());

        if (!stateFunction.returnType().equals(stateType))
        {
            throw ire("State function %s return type must be the same as the first argument type - check STYPE, argument and return types",
                      stateFunctionString());
        }

        /*
         * Resolve the final function and return type
         */

        UserFunction finalFunction = null;
        AbstractType<?> returnType = stateFunction.returnType();

        if (null != finalFunctionName)
        {
            finalFunction = keyspace.userFunctions.find(finalFunctionName, singletonList(stateType)).orElse(null);
            if (null == finalFunction)

View on GitHub (pinned to 88fd0f6a0e)