apache/cassandra · error · InvalidRequestException
Cannot replace function
Error message
Cannot replace function '%s', the new return type %s is not compatible with the return type %s of existing function
What it means
When replacing an existing UDF with OR REPLACE, the new return type must be compatible with (usable in place of) the existing function's return type, so dependent aggregates and clients remain valid. If returnType.isCompatibleWith(existing.returnType()) is false, the statement throws this InvalidRequestException.
Solutions
- Keep the return type identical to the existing function's type
- Drop dependent aggregates, drop and recreate the function with the new type, then recreate the aggregates
- Check the current type in system_schema.functions before replacing
Example fix
// before CREATE OR REPLACE FUNCTION ks.f(int) RETURNS NULL ON NULL INPUT RETURNS text ... -- existing returns int // after CREATE OR REPLACE FUNCTION ks.f(int) RETURNS NULL ON NULL INPUT RETURNS int ...
Defensive patterns
Strategy: validation
Validate before calling
ResultSet rs = session.execute("SELECT return_type FROM system_schema.functions WHERE keyspace_name = ? AND function_name = ?", ks, fn);
String existingReturn = rs.all().get(0).getString(0);
if (!existingReturn.equalsIgnoreCase(newReturnType)) throw new IllegalStateException("Return type changed: " + existingReturn + " -> " + newReturnType); Try / catch
try { session.execute(stmt); } catch (InvalidRequestException e) { if (e.getMessage().contains("not compatible with the return type")) { /* keep original type or plan drop/recreate */ } else throw e; } Prevention
- Treat UDF return types as immutable API surface
- Plan type changes via drop/recreate with dependent aggregate handling
- Compare against system_schema.functions before OR REPLACE
When it happens
Trigger: CREATE OR REPLACE FUNCTION changing the RETURNS type incompatibly, e.g. from int to text, or between incompatible UDTs.
Common situations: Evolving a UDF's return type while aggregates or application code depend on it; tools regenerating function DDL with changed types; accidental type changes when copying definitions.
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
- Function ' ' must have directive
- Argument ' ' cannot be frozen; remove frozen<> modifier from
- Argument ' ' cannot be frozen; remove frozen<> modifier from
- Cannot assign value to of type
- Cannot assign value to of type
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/37edd3a76da73465.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateFunctionStatement.java:157
if (existingFunction.isAggregate())
throw ire("Function '%s' cannot replace an aggregate", functionName);
if (ifNotExists)
return schema;
if (!orReplace)
throw ire("Function '%s' already exists", functionName);
if (calledOnNullInput != ((UDFunction) existingFunction).isCalledOnNullInput())
{
throw ire("Function '%s' must have %s directive",
functionName,
calledOnNullInput ? "CALLED ON NULL INPUT" : "RETURNS NULL ON NULL INPUT");
}
if (!returnType.isCompatibleWith(existingFunction.returnType()))
{
throw ire("Cannot replace function '%s', the new return type %s is not compatible with the return type %s of existing function",
functionName,
returnType.asCQL3Type(),
existingFunction.returnType().asCQL3Type());
}
// TODO: update dependent aggregates
}
return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.userFunctions.withAddedOrUpdated(function)));
}
SchemaChange schemaChangeEvent(KeyspacesDiff diff)
{
assert diff.altered.size() == 1;
FunctionsDiff<UDFunction> udfsDiff = diff.altered.get(0).udfs;
assert udfsDiff.created.size() + udfsDiff.altered.size() == 1;
boolean created = !udfsDiff.created.isEmpty();View on GitHub (pinned to 88fd0f6a0e)