apache/cassandra · error · InvalidRequestException
Final function doesn't exist
Error message
Final function %s doesn't exist
What it means
Thrown by CreateAggregateStatement.apply when a CREATE AGGREGATE statement names a FINALFUNC that does not exist in the target keyspace with a signature of exactly one argument of the aggregate's state type. Cassandra resolves the final function during schema application and refuses to create the aggregate if it cannot be found.
Solutions
- Create the missing scalar function first: CREATE FUNCTION <ks>.<finalfunc>(state <stateType>) RETURNS NULL ON NULL INPUT ...
- Verify the final function's argument type exactly matches the aggregate's STYPE.
- Check you are in the same keyspace (or fully qualify the function name with the keyspace).
- If the aggregate needs no final transformation, drop the FINALFUNC clause entirely.
Example fix
// before CREATE AGGREGATE ks.avg(int) SFUNC avg_state STYPE avg_state FINALFUNC divide_by_count; // (divide_by_count(int) does not exist) // after CREATE FUNCTION ks.divide_by_count(total avg_state) RETURNS NULL ON NULL INPUT RETURNS int ...; CREATE AGGREGATE ks.avg(int) SFUNC avg_state STYPE avg_state FINALFUNC divide_by_count;
Defensive patterns
Strategy: validation
Validate before calling
// pseudocode before CREATE AGGREGATE
var finalFunc = keyspace.userFunctions.find(finalFuncName, List.of(stateType));
if (finalFunc.isEmpty()) throw new IllegalStateException(
"FINALFUNC " + finalFuncName + "(" + stateType + ") not found in keyspace " + keyspace); Try / catch
// catch InvalidRequestException from session.execute
try { session.execute(ddl); }
catch (InvalidRequestException e) {
if (e.getMessage().contains("doesn't exist")) { /* create the final function, then retry */ }
else throw e;
} Prevention
- Create all scalar functions before aggregates in DDL scripts.
- Qualify function names with the keyspace explicitly.
- Keep STYPE and FINALFUNC argument type in sync in one place (a shared template).
When it happens
Trigger: CREATE AGGREGATE ... FINALFUNC <name> where no user-defined scalar function of that name accepting a single argument of the state type exists in the keyspace (or the function exists but with a different argument type).
Common situations: Typo in the final function name; final function created in a different keyspace than the aggregate; final function declared with a parameter type that differs from the state type; FINALFUNC created after the aggregate was attempted.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Final function isn't a scalar function
- ACCESS TO DATACENTERS operations not supported by…
- Aggregate ' ' already exists
- Aggregate ' ' cannot replace a function
- Argument ' ' cannot be frozen; remove frozen<> modifier from
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/278d9d3958c82b59.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateAggregateStatement.java:160
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)
throw ire("Final function %s doesn't exist", finalFunctionString());
if (finalFunction.isAggregate())
throw ire("Final function %s isn't a scalar function", finalFunctionString());
// override return type with that of the final function
returnType = finalFunction.returnType();
}
/*
* Validate initial condition
*/
ByteBuffer initialValue = null;
if (null != rawInitialValue)
{
String term = rawInitialValue.toString();
initialValue = Term.asBytes(keyspaceName, term, stateType);
View on GitHub (pinned to 88fd0f6a0e)