apache/druid · error · IllegalArgumentException
Expected a TableDataSource, got data source type [%s]
Error message
Expected a TableDataSource, got data source type [%s]
What it means
RestrictedDataSource.create() wraps a base data source with a row-level access policy, but only TableDataSource bases are supported. If the supplied base is any other DataSource subtype (lookup, inline, union, query, etc.), it throws IAE naming the actual type. This is upfront type validation before constructing the restricted view.
Source
Thrown at processing/src/main/java/org/apache/druid/query/RestrictedDataSource.java:78
public Policy getPolicy()
{
return policy;
}
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);
}View on GitHub (pinned to 9b90983fd2)
Solutions
- Use a TableDataSource (a druid table) as the base for RestrictedDataSource.
- If you need to restrict a non-table source, apply the policy at a different layer or convert the source into a table first.
- Verify the serialized 'base' field resolves to type 'table' and not another DataSource subtype.
- Confirm no config templating accidentally replaces the base with a lookup/inline/query data source.
Example fix
// before
DataSource base = new LookupDataSource("my_lookup");
RestrictedDataSource rds = RestrictedDataSource.create(base, policy);
// after
DataSource base = new TableDataSource(TableDataSource.name("my_table"));
if (!(base instanceof TableDataSource)) {
throw new IllegalArgumentException("RestrictedDataSource requires a table base");
}
RestrictedDataSource rds = RestrictedDataSource.create(base, policy); Defensive patterns
Strategy: type-guard
Validate before calling
if (!(base instanceof TableDataSource)) {
throw new IllegalArgumentException("RestrictedDataSource.create requires a TableDataSource base, got: "
+ base.getClass().getSimpleName());
}
if (policy == null) {
throw new IllegalArgumentException("Policy must be non-null");
} Type guard
static boolean isRestrictable(DataSource base) {
return base instanceof TableDataSource;
} Try / catch
try {
RestrictedDataSource rds = RestrictedDataSource.create(base, policy);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Expected a TableDataSource")) {
throw new IllegalArgumentException("Configured base must be a druid table, was: "
+ base.getClass().getSimpleName(), e);
}
throw e;
} Prevention
- Validate the 'base' field type ('table') when parsing restricted-data-source configs
- Add a config-schema check that rejects non-table bases before runtime
- Test JSON deserialization of restricted data source configs with all base variants
When it happens
Trigger: Calling RestrictedDataSource.create(base, policy) — directly or via JSON deserialization of the @JsonProperty 'base' — with a base that is not a TableDataSource.
Common situations: Authoring catalog/resource configs that apply row filters to non-table data sources; JSON round-trips producing an unexpected base type; copy-pasted configs that swap an inline or lookup source into a restricted-data-source block.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Cannot deserialize type[%s] to an RoaringBitmap64Counter:
- Expected a number or an instance of MergingDigest, but recei
- Object is not of a type that can be deserialized to a quanti
- Object is not of a type that can be deserialized to a KllFlo
- Object is not of a type that can be deserialized to a quanti
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/fbf42372cd270db4.
Report an issue: GitHub.