apache/iceberg · error · IllegalStateException
Cannot wrap catalog that does not produce BaseTable
Error message
Cannot wrap catalog that does not produce BaseTable
What it means
CatalogHandlers.createTable expects the catalog's result to be a BaseTable so it can wrap the underlying TableMetadata into a LoadTableResponse. If the returned Table is not a BaseTable (e.g. a proxy/wrapper from a custom catalog), this IllegalStateException is thrown — an internal contract violation: catalogs behind the REST handler must produce BaseTable instances.
Solutions
- Make the custom catalog return BaseTable (unwrap the delegate's table in createTable)
- Unwrap nested wrappers to the underlying BaseTable before returning
- Use a catalog implementation known to produce BaseTable
- Ensure the wrapper exposes the BaseTable contract (operations(), current metadata)
Example fix
// before return wrappedTable; // custom wrapper, not BaseTable // after Table t = delegateCatalog.createTable(ident, schema, spec, props); return t instanceof BaseTable ? t : ((BaseTable) unwrap(t));
Defensive patterns
Strategy: type-guard
Validate before calling
Table t = catalog.createTable(ident, schema, spec, props);
if (!(t instanceof BaseTable)) {
throw new IllegalArgumentException("Catalog must return BaseTable, got: " + t.getClass());
} Type guard
boolean isBaseTable(Table t) {
return t instanceof BaseTable;
} Try / catch
try {
CatalogHandlers.createTable(catalog, ns, request);
} catch (IllegalStateException e) {
if (e.getMessage().contains("BaseTable")) {
// fix the catalog adapter to return BaseTable
}
} Prevention
- Test custom catalogs against the REST handler before deploying
- Delegate to a standard catalog and return its BaseTable directly
- Avoid double-wrapping Table objects in routing/proxy layers
When it happens
Trigger: Wiring a custom Catalog implementation that returns wrapped Table objects (not BaseTable) into the REST catalog handler and creating a table through it.
Common situations: Custom or third-party catalog adapters (routing, caching, multi-tenant proxies) returning decorated Table wrappers; forgetting to unwrap to the delegate's BaseTable.
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
- Cannot assume role to sign REST requests because is not…
- Cannot build StorageCredential, some of required attributes…
- Cannot find plan with id
- Cannot initialize AuthManager implementation
- Cannot initialize AuthManager
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/ea3fbbf74c6d922f.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/rest/CatalogHandlers.java:465
request.validate();
TableIdentifier ident = TableIdentifier.of(namespace, request.name());
Table table =
catalog
.buildTable(ident, request.schema())
.withLocation(request.location())
.withPartitionSpec(request.spec())
.withSortOrder(request.writeOrder())
.withProperties(request.properties())
.create();
if (table instanceof BaseTable) {
return LoadTableResponse.builder()
.withTableMetadata(((BaseTable) table).operations().current())
.build();
}
throw new IllegalStateException("Cannot wrap catalog that does not produce BaseTable");
}
public static LoadTableResponse registerTable(
Catalog catalog, Namespace namespace, RegisterTableRequest request) {
request.validate();
TableIdentifier identifier = TableIdentifier.of(namespace, request.name());
Table table =
catalog.registerTable(identifier, request.metadataLocation(), request.overwrite());
if (table instanceof BaseTable) {
return LoadTableResponse.builder()
.withTableMetadata(((BaseTable) table).operations().current())
.build();
}
throw new IllegalStateException("Cannot wrap catalog that does not produce BaseTable");
}
View on GitHub (pinned to 86d9c8fc54)