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

  1. Keep the return type identical to the existing function's type
  2. Drop dependent aggregates, drop and recreate the function with the new type, then recreate the aggregates
  3. 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

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


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)