apache/cassandra · error · InvalidRequestException

Function ' ' must have directive

Error message

Function '%s' must have %s directive

What it means

When OR REPLACE replaces an existing UDF, Cassandra requires the null-input behavior directive to match: a replacement declared CALLED ON NULL INPUT cannot replace one declared RETURNS NULL ON NULL INPUT, and vice versa. The statement compares calledOnNullInput against the existing UDFunction's flag and throws when they differ.

Solutions

  1. Match the existing directive in the OR REPLACE statement
  2. Drop and recreate the function if the null-input semantics must genuinely change
  3. Query system_schema.functions to check the existing function's called_on_null_input flag first

Example fix

// before
CREATE OR REPLACE FUNCTION ks.f(int) CALLED ON NULL INPUT RETURNS int ...  -- existing is RETURNS NULL ON NULL INPUT
// 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 called_on_null_input FROM system_schema.functions WHERE keyspace_name = ? AND function_name = ?", ks, fn);
boolean existing = rs.all().get(0).getBool(0);
if (existing != newCalledOnNullInput) throw new IllegalStateException("Directive mismatch for " + fn);

Try / catch

try { session.execute(stmt); } catch (InvalidRequestException e) { if (e.getMessage().contains("must have")) { /* align CALLED/RETURNS ON NULL INPUT directive */ } else throw e; }

Prevention

When it happens

Trigger: CREATE OR REPLACE FUNCTION where the new declaration's CALLED ON NULL INPUT / RETURNS NULL ON NULL INPUT directive differs from the existing function's directive.

Common situations: Changing a function's null-handling semantics during an update; copying a function body but altering the directive; schema generated by tools that default the directive differently.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateFunctionStatement.java:150

                              calledOnNullInput,
                              language,
                              body);

        UserFunction existingFunction = keyspace.userFunctions.find(function.name(), argumentTypes).orElse(null);
        if (null != existingFunction)
        {
            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)));
    }

View on GitHub (pinned to 88fd0f6a0e)