prestodb/presto · error · PrestoException
INVALID_FUNCTION_ARGUMENT
INVALID_FUNCTION_ARGUMENT
Error message
the size of fromType and toType must match
What it means
RowToRowCast specializes the ROW(F...) -> ROW(T...) cast. The generated row cast requires source and target rows to have the same number of fields; when the type variables have differing field counts it throws INVALID_FUNCTION_ARGUMENT, since a cast between different-arity rows cannot be generated.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/operator/scalar/RowToRowCast.java:86
public class RowToRowCast
extends SqlOperator
{
public static final RowToRowCast ROW_TO_ROW_CAST = new RowToRowCast();
private RowToRowCast()
{
super(CAST, ImmutableList.of(withVariadicBound("F", "row"), withVariadicBound("T", "row")), ImmutableList.of(), parseTypeSignature("T"), ImmutableList.of(parseTypeSignature("F")));
}
@Override
public BuiltInScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, FunctionAndTypeManager functionAndTypeManager)
{
checkArgument(arity == 1, "Expected arity to be 1");
Type fromType = boundVariables.getTypeVariable("F");
Type toType = boundVariables.getTypeVariable("T");
if (fromType.getTypeParameters().size() != toType.getTypeParameters().size()) {
throw new PrestoException(StandardErrorCode.INVALID_FUNCTION_ARGUMENT, "the size of fromType and toType must match");
}
Class<?> castOperatorClass = generateRowCast(fromType, toType, functionAndTypeManager);
MethodHandle methodHandle = methodHandle(castOperatorClass, "castRow", SqlFunctionProperties.class, Block.class);
return new BuiltInScalarFunctionImplementation(
false,
ImmutableList.of(valueTypeArgumentProperty(RETURN_NULL_ON_NULL)),
methodHandle);
}
private static Class<?> generateRowCast(Type fromType, Type toType, FunctionAndTypeManager functionAndTypeManager)
{
List<Type> toTypes = toType.getTypeParameters();
List<Type> fromTypes = fromType.getTypeParameters();
CallSiteBinder binder = new CallSiteBinder();
// Embed the SHA256 hash code of input and output types into the generated class name instead of the raw type names,
// which could prevent the class name from hitting the length limitation and invalid characters.View on GitHub (pinned to 55bb57d202)
Solutions
- Make the CAST target row type have the same number of fields as the source (add or remove fields to match).
- Rebuild the row explicitly: use row field access (r[1], r[2], ...) and construct a new row of the desired arity.
- Fix upstream schema so row arity is stable, or version the row type.
- Use try_cast to get NULL instead of failing while migrating.
Example fix
-- before SELECT CAST(r AS ROW(a INTEGER, b INTEGER)); -- r is ROW(x,y,z) -- after SELECT CAST(ROW(r[1], r[2]) AS ROW(a INTEGER, b INTEGER));
Defensive patterns
Strategy: type-guard
Validate before calling
WHERE cardinality(typehints(fromType)) = cardinality(typehints(toType)) -- ensure same field count before CAST
Try / catch
SELECT try_cast(r AS ROW(a INTEGER, b INTEGER)) AS r2;
When it happens
Trigger: Executing CAST(row_value AS ROW(a, b)) where row_value's row type has a different number of fields than the target (e.g. casting ROW(1,2,3) to ROW(x INT, y INT)).
Common situations: Schema drift: an upstream table's row column gained/lost a field while downstream casts still assume the old arity; hand-written casts omitting a field.
Related errors
- INVALID_CAST_ARGUMENT
- INVALID_CAST_ARGUMENT
- INVALID_CAST_ARGUMENT
- INVALID_TABLE_PROPERTY
- Invalid time from server:
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/5abbf1ceef0c19e1.
Report an issue: GitHub.