{"record":{"id":"2a1d4d9587ef410e","repo":"apache/druid","slug":"cannot-provide-columns-for-an-inline-table","errorCode":null,"errorMessage":"Cannot provide columns for an inline table","messagePattern":"Cannot provide columns for an inline table","errorType":"validation","errorClass":"IAE","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/catalog/model/table/InlineInputSourceDefn.java","lineNumber":117,"sourceCode":"          \"An inline table requires one or more rows of data in the '%s' property\",\n          DATA_PROPERTY\n      );\n    }\n    jsonMap.put(DATA_FIELD, String.join(\"\\n\", data));\n  }\n\n  @Override\n  protected ExternalTableSpec convertCompletedTable(\n      final ResolvedExternalTable table,\n      final Map<String, Object> args,\n      final List<ColumnSpec> columns\n  )\n  {\n    if (!args.isEmpty()) {\n      throw new ISE(\"Cannot provide arguments for an inline table\");\n    }\n    if (!CollectionUtils.isNullOrEmpty(columns)) {\n      throw new IAE(\"Cannot provide columns for an inline table\");\n    }\n    return convertTable(table);\n  }\n\n  @Override\n  protected void auditInputSource(Map<String, Object> jsonMap)\n  {\n    // Special handling of the data property which, in SQL, is a null-delimited\n    // list of rows. The user will usually provide a trailing newline which should\n    // not be interpreted as an empty data row. That is, if the data ends with\n    // a newline, the inline input source will interpret that as a blank line, oddly.\n    String data = CatalogUtils.getString(jsonMap, DATA_FIELD);\n    if (data != null && !data.endsWith(\"\\n\")) {\n      jsonMap.put(DATA_FIELD, data + \"\\n\");\n    }\n  }\n}\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/catalog/model/table/InlineInputSourceDefn.java#L99-L135","documentation":"InlineInputSourceDefn.convertCompletedTable rejects a non-empty columns list because columns for a completed inline table are already part of the resolved table spec. Supplying them again is contradictory and throws IllegalArgumentException.","triggerScenarios":"Calling convertCompletedTable for an inline table with a non-null, non-empty columns list.","commonSituations":"Shared conversion helper that passes columns for all input source types; code migrated from the args-based convertArgsToSourceMap path where columns were expected; copy-paste of another definition's convertCompletedTable call.","solutions":["Pass null or an empty list for the columns parameter when the input source is inline","Ensure the table spec itself contains the columns","If columns must be supplied, use the args-based conversion path instead"],"exampleFix":"// before\ndefn.convertCompletedTable(table, Collections.emptyMap(), columns);\n// after\ndefn.convertCompletedTable(table, Collections.emptyMap(), null);","handlingStrategy":"validation","validationCode":"if (columns != null && !columns.isEmpty()) {\n  throw new IllegalArgumentException(\"inline convertCompletedTable requires null/empty columns\");\n}","typeGuard":null,"tryCatchPattern":"try { defn.convertCompletedTable(table, args, columns); } catch (IAE e) { if (e.getMessage().contains(\"Cannot provide columns\")) { columns = null; /* retry */ } else { throw e; } }","preventionTips":["For inline, always place columns in the table spec, never in the conversion call","Use type-specific conversion helpers rather than a generic one","Review conversions after refactors that changed the columns contract"],"tags":["inline","input-source","api-misuse","columns"],"backgroundTag":"invalid-argument","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}