apache/druid · error · IllegalStateException
Missing policy check result for table [%s]
Error message
Missing policy check result for table [%s]
What it means
When a query containing a RestrictedDataSource flows through policy re-checking, withPolicies requires the policyMap to contain an entry for the base table name — even if the entry is Optional.empty(). A missing key means the enforcer never evaluated that table, which Druid treats as an internal invariant violation (ISE) rather than silently dropping restrictions.
Source
Thrown at processing/src/main/java/org/apache/druid/query/RestrictedDataSource.java:143
@Override
public SegmentMapFunction createSegmentMapFunction(Query query)
{
return base.createSegmentMapFunction(query).thenMap(segment -> new RestrictedSegment(segment, policy));
}
@Nullable
@Override
public SegmentPruner createSegmentPruner()
{
return policy.createSegmentPruner();
}
@Override
public DataSource withPolicies(Map<String, Optional<Policy>> policyMap, PolicyEnforcer policyEnforcer)
{
if (!policyMap.containsKey(base.getName())) {
throw new ISE("Missing policy check result for table [%s]", base.getName());
}
Optional<Policy> newPolicy = policyMap.getOrDefault(base.getName(), Optional.empty());
if (newPolicy.isEmpty() || newPolicy.get() instanceof NoRestrictionPolicy) {
// allow empty policy, which means no restriction.
// druid-internal calls with NoRestrictionPolicy: allow
} else if (newPolicy.get().equals(policy)) {
// same policy: allow
} else {
throw new ISE(
"Different restrictions on table [%s]: previous policy [%s] and new policy [%s]",
base.getName(),
policy,
newPolicy.get()
);
}
// The only happy path is, newPolicy is NoRestrictionPolicy, which means this comes from an anthenticated and
// authorized druid-internal request.View on GitHub (pinned to 9b90983fd2)
Solutions
- Fix the PolicyEnforcer to emit an entry for every input table, using Optional.empty() for unrestricted tables
- Verify the table name used as the map key matches base.getName() (check for aliasing/renaming)
- Wrap the enforcer to add missing keys as Optional.empty() before calling withPolicies
Example fix
// before
Map<String, Optional<Policy>> results = enforcer.getPolicies(tables.subList(0, 1));
restricted.withPolicies(results, enforcer);
// after
Map<String, Optional<Policy>> results = enforcer.getPolicies(tables); // entry for every table
if (!results.containsKey(restricted.getName())) {
results.put(restricted.getName(), Optional.empty());
}
restricted.withPolicies(results, enforcer); Defensive patterns
Strategy: try-catch
Validate before calling
if (!policyMap.containsKey(restrictedDs.getName())) {
throw new IllegalStateException("Enforcer missing result for table " + restrictedDs.getName());
} Try / catch
try {
DataSource ds = restricted.withPolicies(policyMap, enforcer);
} catch (IllegalStateException e) {
// re-run enforcer over all tables and retry once
} Prevention
- Require PolicyEnforcer implementations to return results for every input table
- Key policy maps by the exact datasource/table name used by Druid
- Test custom enforcers with multi-table queries
When it happens
Trigger: Calling withPolicies(policyMap, enforcer) where policyMap lacks a key equal to base.getName(); a PolicyEnforcer that only populates results for tables it considers relevant, skipping restricted tables.
Common situations: Custom PolicyEnforcer returning a partial result map; table renamed or aliased so the enforcer keyed results by a different name; running through systems (e.g. druid-internal MSQ/centralized datasource logic) that rebuild the policy map from a subset of tables.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Policy can't be null for RestrictedDataSource
- Different restrictions on table [%s]: previous policy [%s] a
- Not computing rollup
- Not computing queryGranularity
- Not computing dimensionsSpec
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/3f423fd96ebe5500.
Report an issue: GitHub.