{"record":{"id":"a247dc1ccab1b0aa","repo":"apache/druid","slug":"rules-cannot-be-null","errorCode":null,"errorMessage":"Rules cannot be null.","messagePattern":"Rules cannot be null\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/metadata/SQLMetadataRuleManager.java","lineNumber":314,"sourceCode":"        log.makeAlert(e, \"Exception while polling for rules\").emit();\n        failStartTimeMs = 0;\n      } else {\n        log.error(e, \"Exception while polling for rules\");\n      }\n    }\n  }\n\n  @Override\n  public RetentionRulesSnapshot getRulesSnapshot()\n  {\n    return rulesSnapshot.get();\n  }\n\n  @Override\n  public boolean overrideRule(final String dataSource, final List<Rule> newRules, final AuditInfo auditInfo)\n  {\n    if (newRules == null) {\n      throw new IAE(\"Rules cannot be null.\");\n    } else if (newRules.isEmpty() && config.getDefaultRule().equals(dataSource)) {\n      throw new IAE(\"Cluster-level rules cannot be empty.\");\n    }\n\n    final String ruleString;\n    try {\n      ruleString = jsonMapper.writeValueAsString(newRules);\n      // uses getAllRules over getOverrideRules to allow proper audit trail when setting explicit [] override rules for\n      // a datasource with no existing overrides.\n      if (ruleString.equals(jsonMapper.writeValueAsString(rulesSnapshot.get().getAllRules().get(dataSource)))) {\n        log.info(\"Retention rules unchanged for datasource[%s] with rules[%s]\", dataSource, ruleString);\n        return true;\n      }\n      log.info(\"Updating datasource[%s] with rules[%s] as per [%s]\", dataSource, ruleString, auditInfo);\n    }\n    catch (JsonProcessingException e) {\n      log.error(e, \"Unable to write rules as string for datasource[%s]\", dataSource);\n      return false;","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/metadata/SQLMetadataRuleManager.java#L296-L332","documentation":"SQLMetadataRuleManager.overrideRule() persists an override of the load rules for a datasource. It throws IllegalArgumentException when the newRules list is null; an empty list is allowed (meaning 'no rules for this datasource, fall back to cluster defaults') but null is not a valid rule set.","triggerScenarios":"POSTing to the coordinator rules endpoint with a null 'rules' field; programmatic calls to overrideRule(dataSource, null, auditInfo); deserialization of a request body that omits the rules array.","commonSituations":"Automation scripts building rule payloads conditionally and omitting the rules key; API clients sending JSON without the rules property; migration tooling between rule APIs.","solutions":["Pass an empty list instead of null when you intend to clear datasource-specific rules.","Fix the API client so the request body always includes a rules array.","Add a null check on the rules list in the calling code before invoking overrideRule."],"exampleFix":"// before\nruleManager.overrideRule(dataSource, newRules, auditInfo); // newRules may be null\n// after\nruleManager.overrideRule(dataSource, newRules == null ? Collections.emptyList() : newRules, auditInfo);","handlingStrategy":"type-guard","validationCode":"if (rules == null) rules = Collections.emptyList();","typeGuard":"List<Rule> safeRules(List<Rule> rules) { return rules == null ? Collections.emptyList() : rules; }","tryCatchPattern":"try {\n  ruleManager.overrideRule(dataSource, rules, auditInfo);\n} catch (IllegalArgumentException e) {\n  log.error(e, \"Rule override rejected: %s\", e.getMessage());\n}","preventionTips":["Always serialize rules as an array (possibly empty) in API payloads","Deserialize request bodies with null-tolerant defaults","Document that empty list clears overrides, null is invalid"],"tags":["rules","null-argument","rest-api"],"backgroundTag":"null-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"}