{"record":{"id":"ed7dc955a7eecffa","repo":"apache/druid","slug":"policy-can-t-be-null-for-restricteddatasource","errorCode":null,"errorMessage":"Policy can't be null for RestrictedDataSource","messagePattern":"Policy can't be null for RestrictedDataSource","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/RestrictedDataSource.java","lineNumber":81,"sourceCode":"  }\n\n  RestrictedDataSource(TableDataSource base, Policy policy)\n  {\n    this.base = base;\n    this.policy = policy;\n  }\n\n  @JsonCreator\n  public static RestrictedDataSource create(\n      @JsonProperty(\"base\") DataSource base,\n      @JsonProperty(\"policy\") Policy policy\n  )\n  {\n    if (!(base instanceof TableDataSource)) {\n      throw new IAE(\"Expected a TableDataSource, got data source type [%s]\", base.getClass());\n    }\n    if (Objects.isNull(policy)) {\n      throw new IAE(\"Policy can't be null for RestrictedDataSource\");\n    }\n    return new RestrictedDataSource((TableDataSource) base, policy);\n  }\n\n  @Override\n  public Set<String> getTableNames()\n  {\n    return base.getTableNames();\n  }\n\n  @Override\n  public List<DataSource> getChildren()\n  {\n    return ImmutableList.of(base);\n  }\n\n  @Override\n  public DataSource withChildren(List<DataSource> children)","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/RestrictedDataSource.java#L63-L99","documentation":"RestrictedDataSource.wrap requires a non-null row-level Policy object when wrapping a TableDataSource in a policy-restricted data source. A null policy is ambiguous (does it mean 'no restriction' or an unfinished policy-resolution step?), so Druid rejects it eagerly with IAE rather than building a half-initialized data source. Callers should pass Optional.empty()/NoRestrictionPolicy semantics explicitly instead of null.","triggerScenarios":"Calling RestrictedDataSource.create(base, null) or the JSON-creatable factory with a null policy field, typically when a policy lookup in the enforcer returned null instead of Optional.empty().","commonSituations":"Custom PolicyEnforcer implementations that return null from a map lookup; policy metadata missing in external catalog so the resolved policy is null; tests constructing RestrictedDataSource without a policy.","solutions":["Ensure the policy-enforcement layer supplies a non-null Policy before calling create; map 'no restriction' to Optional.empty() or NoRestrictionPolicy","Audit the PolicyEnforcer/catalog lookup for paths that return null and convert them to Optional.empty()","If the caller itself is at fault, add a null check before invoking RestrictedDataSource.create"],"exampleFix":"// before\nPolicy policy = policyMap.get(tableName); // may be null\nreturn RestrictedDataSource.create(base, policy);\n// after\nPolicy policy = Optional.ofNullable(policyMap.get(tableName)).orElse(new NoRestrictionPolicy());\nreturn RestrictedDataSource.create(base, policy);","handlingStrategy":"validation","validationCode":"if (policy == null) {\n  throw new IllegalArgumentException(\"Policy must be provided; use Optional.empty()/NoRestrictionPolicy for no restriction\");\n}\nRestrictedDataSource.create(base, policy);","typeGuard":"boolean isRestrictable(DataSource base, Policy policy) {\n  return base instanceof TableDataSource && policy != null;\n}","tryCatchPattern":"try {\n  DataSource ds = RestrictedDataSource.create(base, policy);\n} catch (IllegalArgumentException e) {\n  // handle missing policy: fall back to unrestricted source or surface config error\n}","preventionTips":["Never pass raw null Policy; always normalize to Optional/NoRestrictionPolicy upstream","Null-check policy in PolicyEnforcer result paths"],"tags":["druid","null-argument","datasource","policy"],"backgroundTag":"null-argument","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}