{"record":{"id":"ecc630223ad2e4d8","repo":"prestodb/presto","slug":"invalid-function-argument-ecc630","errorCode":"INVALID_FUNCTION_ARGUMENT","errorMessage":"COLUMNS descriptor is null","messagePattern":"COLUMNS descriptor is null","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/operator/table/ExcludeColumns.java","lineNumber":92,"sourceCode":"                    \"builtin\",\n                    NAME,\n                    ImmutableList.of(\n                            TableArgumentSpecification.builder()\n                                    .name(TABLE_ARGUMENT_NAME)\n                                    .rowSemantics()\n                                    .build(),\n                            DescriptorArgumentSpecification.builder()\n                                    .name(DESCRIPTOR_ARGUMENT_NAME)\n                                    .build()),\n                    GENERIC_TABLE);\n        }\n\n        @Override\n        public TableFunctionAnalysis analyze(ConnectorSession session, ConnectorTransactionHandle transaction, Map<String, Argument> arguments)\n        {\n            DescriptorArgument excludedColumns = (DescriptorArgument) arguments.get(DESCRIPTOR_ARGUMENT_NAME);\n            if (excludedColumns.equals(NULL_DESCRIPTOR)) {\n                throw new PrestoException(INVALID_FUNCTION_ARGUMENT, \"COLUMNS descriptor is null\");\n            }\n            Descriptor excludedColumnsDescriptor = excludedColumns.getDescriptor().orElseThrow(() -> new PrestoException(INVALID_ARGUMENTS, \"Missing exclude columns descriptor\"));\n            if (excludedColumnsDescriptor.getFields().stream().anyMatch(field -> field.getType().isPresent())) {\n                throw new PrestoException(INVALID_FUNCTION_ARGUMENT, \"COLUMNS descriptor contains types\");\n            }\n\n            // column names in DescriptorArgument are canonical wrt SQL identifier semantics.\n            // column names in TableArgument are not canonical wrt SQL identifier semantics, as they are taken from the corresponding RelationType.\n            // because of that, we match the excluded columns names case-insensitive\n            // TODO: apply proper identifier semantics\n            Set<String> excludedNames = excludedColumnsDescriptor.getFields().stream()\n                    .map(Descriptor.Field::getName)\n                    .map(name -> name.orElseThrow(() -> new PrestoException(INVALID_ARGUMENTS, \"Missing Descriptor field name\")).toLowerCase(ENGLISH))\n                    .collect(toImmutableSet());\n\n            List<RowType.Field> inputSchema = ((TableArgument) arguments.get(TABLE_ARGUMENT_NAME)).getRowType().getFields();\n            Set<String> inputNames = inputSchema.stream()\n                    .map(RowType.Field::getName)","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/operator/table/ExcludeColumns.java#L74-L110","documentation":"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.","triggerScenarios":"Calling TABLE(exclude_columns(TABLE => t, COLUMNS => NULL)) — passing NULL as the COLUMNS descriptor argument to the exclude_columns table function.","commonSituations":"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.","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"],"exampleFix":"// before\nSELECT * FROM TABLE(exclude_columns(TABLE => t, COLUMNS => NULL));\n// after\nSELECT * FROM TABLE(exclude_columns(TABLE => t, COLUMNS => 'col1 col2')); -- or drop the function if nothing to exclude","handlingStrategy":"validation","validationCode":"if (columnsArg == null) { throw new IllegalArgumentException(\"COLUMNS descriptor must not be null for exclude_columns\"); }","typeGuard":"boolean hasValidDescriptor = arguments.get(\"COLUMNS\") instanceof DescriptorArgument && !((DescriptorArgument) arguments.get(\"COLUMNS\")).equals(NULL_DESCRIPTOR);","tryCatchPattern":"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; }","preventionTips":["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"],"tags":["presto","sql","table-function","null-argument","invalid-function-argument"],"backgroundTag":"null-argument","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}