apache/druid · error · IllegalArgumentException

Policy can't be null for RestrictedDataSource

Error message

Policy can't be null for RestrictedDataSource

What it means

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.

Source

Thrown at processing/src/main/java/org/apache/druid/query/RestrictedDataSource.java:81

  }

  RestrictedDataSource(TableDataSource base, Policy policy)
  {
    this.base = base;
    this.policy = policy;
  }

  @JsonCreator
  public static RestrictedDataSource create(
      @JsonProperty("base") DataSource base,
      @JsonProperty("policy") Policy policy
  )
  {
    if (!(base instanceof TableDataSource)) {
      throw new IAE("Expected a TableDataSource, got data source type [%s]", base.getClass());
    }
    if (Objects.isNull(policy)) {
      throw new IAE("Policy can't be null for RestrictedDataSource");
    }
    return new RestrictedDataSource((TableDataSource) base, policy);
  }

  @Override
  public Set<String> getTableNames()
  {
    return base.getTableNames();
  }

  @Override
  public List<DataSource> getChildren()
  {
    return ImmutableList.of(base);
  }

  @Override
  public DataSource withChildren(List<DataSource> children)

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Ensure the policy-enforcement layer supplies a non-null Policy before calling create; map 'no restriction' to Optional.empty() or NoRestrictionPolicy
  2. Audit the PolicyEnforcer/catalog lookup for paths that return null and convert them to Optional.empty()
  3. If the caller itself is at fault, add a null check before invoking RestrictedDataSource.create

Example fix

// before
Policy policy = policyMap.get(tableName); // may be null
return RestrictedDataSource.create(base, policy);
// after
Policy policy = Optional.ofNullable(policyMap.get(tableName)).orElse(new NoRestrictionPolicy());
return RestrictedDataSource.create(base, policy);
Defensive patterns

Strategy: validation

Validate before calling

if (policy == null) {
  throw new IllegalArgumentException("Policy must be provided; use Optional.empty()/NoRestrictionPolicy for no restriction");
}
RestrictedDataSource.create(base, policy);

Type guard

boolean isRestrictable(DataSource base, Policy policy) {
  return base instanceof TableDataSource && policy != null;
}

Try / catch

try {
  DataSource ds = RestrictedDataSource.create(base, policy);
} catch (IllegalArgumentException e) {
  // handle missing policy: fall back to unrestricted source or surface config error
}

Prevention

When it happens

Trigger: 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().

Common situations: 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.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/ed7dc955a7eecffa. Report an issue: GitHub.