apache/cassandra · error · InvalidRequestException
Masking function return type is . This is different to the…
Error message
Masking function %s return type is %s. This is different to the type of the masked column %s of type %s. Masking functions can only be attached to table columns if they return the same data type as the masked column.
What it means
ColumnMask.findMaskingFunction enforces that the masking function's return type exactly equals the type of the column being masked. Because the masked value replaces the column value in results, a type-changing mask would break type expectations, so mismatched signatures are rejected.
Solutions
- Pick/adjust the masking function so its return type matches the column type exactly (compare CQL3Type).
- For UDFs, add a returns-clause overload matching the column type or create a new function with the correct return type.
- If the column type is wrong for your purpose, ALTER the column semantics first (note Cassandra restricts type changes).
Example fix
// before ALTER TABLE users ALTER email MASKED WITH hash(text); // hash(blob) vs text column // after ALTER TABLE users ALTER email MASKED WITH mask_inner(text, 1, 3, 'x');
Defensive patterns
Strategy: validation
Validate before calling
// verify return type matches column type before DDL
Row r = session.execute("SELECT argument_types, return_type FROM system_schema.functions WHERE keyspace_name=? AND function_name=?", ks, fn).one();
if (r != null && !r.getString("return_type").equals(columnType))
throw new IllegalArgumentException("return type " + r.getString("return_type") + " != column type " + columnType); Prevention
- Map each column type to a masking function of identical return type in your schema conventions doc.
- Re-check masking policies after any column type change.
When it happens
Trigger: MASKED WITH a function whose return type differs from the column type, e.g. col is int but the function returns text, or a hash masking function applied to a non-blob column without matching signature.
Common situations: Applying mask_inner(text,...) to an int column, writing a UDF returning text to mask a bigint column, or after a column type migration the previously valid mask no longer matches.
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
- Aggregate function cannot be used for masking table columns
- Cannot assign value to of type
- Cannot assign value to of type
- Cannot cast value to type
- Cannot replace aggregate
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/ed1f67e39ea4e065.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/functions/masking/ColumnMask.java:262
if (function == null)
throw invalidRequest("Unable to find masking function for %s, " +
"no declared function matches the signature %s",
column, this);
if (function.isAggregate())
throw invalidRequest("Aggregate function %s cannot be used for masking table columns", this);
if (function.isNative() && !(function instanceof MaskingFunction))
throw invalidRequest("Not-masking function %s cannot be used for masking table columns", this);
if (!function.isNative() && !function.name().keyspace.equals(keyspace))
throw invalidRequest("Masking function %s doesn't belong to the same keyspace as the table %s.%s",
this, keyspace, table);
CQL3Type returnType = function.returnType().asCQL3Type();
CQL3Type expectedType = type.asCQL3Type();
if (!returnType.equals(expectedType))
throw invalidRequest("Masking function %s return type is %s. " +
"This is different to the type of the masked column %s of type %s. " +
"Masking functions can only be attached to table columns " +
"if they return the same data type as the masked column.",
this, returnType, column, expectedType);
return (ScalarFunction) function;
}
private ByteBuffer[] preparePartialArguments(String keyspace, ScalarFunction function)
{
// Note that there could be null arguments
ByteBuffer[] arguments = new ByteBuffer[rawPartialArguments.size()];
for (int i = 0; i < rawPartialArguments.size(); i++)
{
String term = rawPartialArguments.get(i).toString();
AbstractType<?> type = function.argTypes().get(i + 1);
arguments[i] = Term.asBytes(keyspace, term, type);View on GitHub (pinned to 88fd0f6a0e)