{"record":{"id":"cfc161fbff4cb8c5","repo":"apache/druid","slug":"at-most-one-of-properties-s-must-be-present","errorCode":null,"errorMessage":"At most one of properties[%s] must be present","messagePattern":"At most 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":40,"sourceCode":"import org.apache.druid.java.util.common.IAE;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * Various helper methods useful for checking the validity of arguments to spec constructors.\n */\npublic 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   */","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/indexer/Checks.java#L22-L58","documentation":"Checks.checkOneNotNullOrEmpty enforces that at most one property from a given set has a non-empty value. If two or more of the listed properties are set, an IAE listing all property names is thrown while parsing the Hadoop batch job/config object.","triggerScenarios":"Constructing or deserializing a Hadoop indexing config (e.g. HadoopIngestionSpec / GranularitySpec-style input specs) where two mutually exclusive properties (like two input path/spec options) are both provided.","commonSituations":"Hadoop batch ingestion specs that specify both inputPaths and a separate input spec; generated JSON templates that fill in multiple optional fields.","solutions":["Remove all but one of the conflicting properties in the ingestion spec.","Use only the property recommended by the current ingestion spec schema.","Regenerate the spec so only the intended input source field is populated."],"exampleFix":"// before\n\"inputPaths\": \"hdfs://a/b\",\n\"inputSpec\": {\"type\": \"static\", \"paths\": \"hdfs://a/b\"}\n// after\n\"inputSpec\": {\"type\": \"static\", \"paths\": \"hdfs://a/b\"}","handlingStrategy":"validation","validationCode":"int present = Stream.of(prop1, prop2, prop3).filter(p -> p.getValue() != null && !isEmptyCollection(p.getValue())).count();\nif (present > 1) { throw new IllegalArgumentException(\"At most one input property may be set\"); }","typeGuard":null,"tryCatchPattern":"try { Checks.checkOneNotNullOrEmpty(p1, p2); } catch (IAE e) { log.error(\"Mutually exclusive properties set: {}\", e.getMessage()); throw e; }","preventionTips":["Set only one of the alternative input properties in ingestion specs","Validate specs with a JSON schema before submission","Avoid merging multiple spec templates blindly"],"tags":["validation","hadoop-ingestion","mutually-exclusive"],"backgroundTag":"mutually-exclusive-options","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"}