{"record":{"id":"1d277d5365f41772","repo":"apache/druid","slug":"at-least-one-of-properties-s-must-be-present","errorCode":null,"errorMessage":"At least one of properties[%s] must be present","messagePattern":"At least one of properties\\[(.+?)\\] must be present","errorType":"validation","errorClass":"IAE","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/indexer/Checks.java","lineNumber":48,"sourceCode":"public final class Checks\n{\n  public static <T> Property<T> checkOneNotNullOrEmpty(List<Property<T>> properties)\n  {\n    Property<T> nonNullProperty = null;\n    for (Property<T> property : properties) {\n      if (!property.isValueNullOrEmptyCollection()) {\n        if (nonNullProperty == null) {\n          nonNullProperty = property;\n        } else {\n          throw new IAE(\n              \"At most one of properties[%s] must be present\",\n              properties.stream().map(Property::getName).collect(Collectors.toList())\n          );\n        }\n      }\n    }\n    if (nonNullProperty == null) {\n      throw new IAE(\n          \"At least one of properties[%s] must be present\",\n          properties.stream().map(Property::getName).collect(Collectors.toList())\n      );\n    }\n    return nonNullProperty;\n  }\n\n  /**\n   * @return Non-null value, or first one if both are null. -1 is interpreted as null for historical reasons.\n   */\n  public static <T> Property<T> checkAtMostOneNotNull(Property<T> property1, Property<T> property2)\n  {\n    final Property<T> property;\n\n    boolean isNull1 = property1.getValue() == null;\n    boolean isNull2 = property2.getValue() == null;\n\n    if (isNull1 && isNull2) {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/indexer/Checks.java#L30-L66","documentation":"Checks.checkOneNotNullOrEmpty is a Hadoop-batch configuration validation helper: it verifies that at least one of the given Druid properties was set, and throws this IAE when all of them are null/empty. It prevents batch ingestion jobs from starting with a required but missing configuration knob.","triggerScenarios":"Building a batch ingestion config object where the required input property (e.g. paths or inputSpec) was omitted entirely, so checkOneNotNullOrEmpty finds no populated property and throws.","commonSituations":"Hand-written Hadoop ingestion specs missing the input path field; programmatic spec builders that skip optional-looking but required-alternative fields.","solutions":["Set at least one of the listed properties in the ingestion spec/Hadoop job configuration.","Check property name spelling in the config; a typo leaves the intended property unset.","Review the calling job type's documentation for which of the mutually-required properties apply."],"exampleFix":"// before\n\"type\": \"index_hadoop\"  // no input property\n// after\n\"inputSpec\": {\"type\": \"static\", \"paths\": \"hdfs://a/b\"}","handlingStrategy":"validation","validationCode":"boolean any = Stream.of(prop1, prop2).anyMatch(p -> p.getValue() != null && !isEmptyCollection(p.getValue()));\nif (!any) { throw new IllegalArgumentException(\"One of the required input properties must be set\"); }","typeGuard":null,"tryCatchPattern":"try { Checks.checkOneNotNullOrEmpty(p1, p2); } catch (IAE e) { log.error(\"No input property provided: {}\", e.getMessage()); throw e; }","preventionTips":["Always populate one input-source field in Hadoop ingestion specs","Use spec-builder utilities instead of raw JSON","Lint specs for empty required alternatives before submitting"],"tags":["validation","hadoop-ingestion","missing-required"],"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-17T15:17:12.973Z"}