{"record":{"id":"7006ec7a83a6baac","repo":"apache/druid","slug":"a-local-input-source-requires-one-property-of-s-o","errorCode":null,"errorMessage":"A local input source requires one property of %s or %s","messagePattern":"A local input source requires one property of (.+?) or (.+?)","errorType":"validation","errorClass":"IAE","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/catalog/model/table/LocalInputSourceDefn.java","lineNumber":88,"sourceCode":"    return LocalInputSource.TYPE_KEY;\n  }\n\n  @Override\n  protected Class<? extends InputSource> inputSourceClass()\n  {\n    return LocalInputSource.class;\n  }\n\n  @Override\n  public void validate(ResolvedExternalTable table)\n  {\n    final Map<String, Object> sourceMap = new HashMap<>(table.inputSourceMap);\n    final boolean hasBaseDir = sourceMap.containsKey(BASE_DIR_FIELD);\n    final boolean hasFiles = !CollectionUtils.isNullOrEmpty(CatalogUtils.safeGet(sourceMap, FILES_FIELD, List.class));\n    final boolean hasFilter = !Strings.isNullOrEmpty(CatalogUtils.getString(sourceMap, FILTER_FIELD));\n\n    if (!hasBaseDir && !hasFiles) {\n      throw new IAE(\n          \"A local input source requires one property of %s or %s\",\n          BASE_DIR_FIELD,\n          FILES_FIELD\n      );\n    }\n    if (!hasBaseDir && hasFilter) {\n      throw new IAE(\n          \"If a local input source sets property %s, it must also set property %s\",\n          FILTER_FIELD,\n          BASE_DIR_FIELD\n      );\n    }\n    if (hasBaseDir && hasFiles) {\n      throw new IAE(\n          \"A local input source accepts only one of %s or %s\",\n          BASE_DIR_FIELD,\n          FILES_FIELD\n      );","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/catalog/model/table/LocalInputSourceDefn.java#L70-L106","documentation":"LocalInputSourceDefn.validate requires a local input source to specify at least one of baseDir or files. Without either, Druid has nothing to read. Thrown as IllegalArgumentException during table validation.","triggerScenarios":"Validating a local ResolvedExternalTable whose inputSourceMap contains neither the baseDir field nor a non-empty files list.","commonSituations":"Local source config created programmatically with neither property set; switching from another source type and deleting paths without adding new ones; partial edits to the source JSON.","solutions":["Set the baseDir property to the directory containing the files","Or provide a non-empty files list of explicit paths","Re-run validation after adding one of the two properties"],"exampleFix":"// before\n{\"type\":\"local\",\"filter\":\"*.csv\"}\n// after\n{\"type\":\"local\",\"baseDir\":\"/data/incoming\",\"filter\":\"*.csv\"}","handlingStrategy":"validation","validationCode":"Map<String,Object> src = table.getInputSourceMap();\nif (!src.containsKey(\"baseDir\")\n    && (src.get(\"files\") == null || ((List<?>) src.get(\"files\")).isEmpty())) {\n  throw new IllegalArgumentException(\"local source needs baseDir or files\");\n}","typeGuard":null,"tryCatchPattern":"try { defn.validate(table); } catch (IAE e) { if (e.getMessage().contains(\"requires one property\")) { /* set baseDir or files */ } else { throw e; } }","preventionTips":["Always pair local source config with either baseDir or a files list","Template checks: fail fast when both path variables are empty","Validate source JSON before catalog save"],"tags":["local","input-source","validation","missing-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}