prestodb/presto · error · PrestoException
INVALID_FUNCTION_ARGUMENT
INVALID_FUNCTION_ARGUMENT
Error message
COLUMNS descriptor is null
What it means
The exclude_columns table function requires its COLUMNS descriptor argument to be a real descriptor, not the sentinel NULL_DESCRIPTOR. During analyze(), if the descriptor argument equals NULL_DESCRIPTOR (the user passed NULL for the COLUMNS argument), Presto throws INVALID_FUNCTION_ARGUMENT because there are no columns to exclude.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/operator/table/ExcludeColumns.java:92
"builtin",
NAME,
ImmutableList.of(
TableArgumentSpecification.builder()
.name(TABLE_ARGUMENT_NAME)
.rowSemantics()
.build(),
DescriptorArgumentSpecification.builder()
.name(DESCRIPTOR_ARGUMENT_NAME)
.build()),
GENERIC_TABLE);
}
@Override
public TableFunctionAnalysis analyze(ConnectorSession session, ConnectorTransactionHandle transaction, Map<String, Argument> arguments)
{
DescriptorArgument excludedColumns = (DescriptorArgument) arguments.get(DESCRIPTOR_ARGUMENT_NAME);
if (excludedColumns.equals(NULL_DESCRIPTOR)) {
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "COLUMNS descriptor is null");
}
Descriptor excludedColumnsDescriptor = excludedColumns.getDescriptor().orElseThrow(() -> new PrestoException(INVALID_ARGUMENTS, "Missing exclude columns descriptor"));
if (excludedColumnsDescriptor.getFields().stream().anyMatch(field -> field.getType().isPresent())) {
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "COLUMNS descriptor contains types");
}
// column names in DescriptorArgument are canonical wrt SQL identifier semantics.
// column names in TableArgument are not canonical wrt SQL identifier semantics, as they are taken from the corresponding RelationType.
// because of that, we match the excluded columns names case-insensitive
// TODO: apply proper identifier semantics
Set<String> excludedNames = excludedColumnsDescriptor.getFields().stream()
.map(Descriptor.Field::getName)
.map(name -> name.orElseThrow(() -> new PrestoException(INVALID_ARGUMENTS, "Missing Descriptor field name")).toLowerCase(ENGLISH))
.collect(toImmutableSet());
List<RowType.Field> inputSchema = ((TableArgument) arguments.get(TABLE_ARGUMENT_NAME)).getRowType().getFields();
Set<String> inputNames = inputSchema.stream()
.map(RowType.Field::getName)View on GitHub (pinned to 55bb57d202)
Solutions
- Pass a non-null COLUMNS descriptor with at least one column name
- Omit the exclude_columns table function entirely if there is nothing to exclude
- In generated SQL, substitute an empty descriptor instead of NULL, or skip the function call when the exclusion list is null
- Validate the exclusion list is non-null before building the query
Example fix
// before SELECT * FROM TABLE(exclude_columns(TABLE => t, COLUMNS => NULL)); // after SELECT * FROM TABLE(exclude_columns(TABLE => t, COLUMNS => 'col1 col2')); -- or drop the function if nothing to exclude
Defensive patterns
Strategy: validation
Validate before calling
if (columnsArg == null) { throw new IllegalArgumentException("COLUMNS descriptor must not be null for exclude_columns"); } Type guard
boolean hasValidDescriptor = arguments.get("COLUMNS") instanceof DescriptorArgument && !((DescriptorArgument) arguments.get("COLUMNS")).equals(NULL_DESCRIPTOR); Try / catch
try { return TABLE(exclude_columns(TABLE => t, COLUMNS => cols)); } catch (PrestoException e) { if (INVALID_FUNCTION_ARGUMENT.toErrorCode().equals(e.getErrorCode())) { /* drop the exclude_columns wrapper and select the table directly */ } throw e; } Prevention
- Never pass NULL as the COLUMNS argument; pass an explicit descriptor or skip the function
- In SQL generators, emit exclude_columns only when the exclusion list is non-null
- Validate user-supplied exclusion lists before query construction
- Handle null/empty list inputs at the application layer with a fallback to plain SELECT
When it happens
Trigger: Calling TABLE(exclude_columns(TABLE => t, COLUMNS => NULL)) — passing NULL as the COLUMNS descriptor argument to the exclude_columns table function.
Common situations: Dynamically built SQL where the column list parameter was null/empty and serialized as NULL; generated queries from ORMs or scripts that substitute null for an empty descriptor list.
Related errors
- INVALID_FUNCTION_ARGUMENT
- INVALID_FUNCTION_ARGUMENT
- TABLE_FUNCTION_DUPLICATE_RANGE_VARIABLE
- INVALID_TABLE_PROPERTY
- Invalid time from server:
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/ecc630223ad2e4d8.
Report an issue: GitHub.