apache/iceberg · error · IllegalArgumentException

Cannot create metadata table for table

Error message

Cannot create metadata table for table %s: table is not a base table or does not have table operations

What it means

IllegalArgumentException thrown when creating a metadata table instance for a Table that does not expose TableOperations (does not implement HasTableOperations). Metadata tables (e.g., table.refs, table.files) can only be built from a real base table backed by Iceberg operations, not from wrapped, generic, or foreign Table implementations. It indicates the object passed in is not a plain Iceberg base table.

Solutions

  1. Load the actual base table from the catalog and request the metadata table from it, not from a wrapped/metadata table.
  2. Verify the Table instance implements HasTableOperations before building metadata tables.
  3. Remove double metadata-table naming (e.g., 'tbl.files.files'); query the base table directly.
  4. In tests, use a real TestTables instance that provides TableOperations.

Example fix

// before
Table files = MetadataTableUtils.createMetadataTableInstance(metadataTable, MetadataTableType.FILES); // IAE
// after
Table baseTable = catalog.loadTable(identifier);
Table files = MetadataTableUtils.createMetadataTableInstance(baseTable, MetadataTableType.FILES);
Defensive patterns

Strategy: validation

Validate before calling

// guard before calling
if (!(table instanceof HasTableOperations)) {
  throw new IllegalArgumentException("Load the base table, not: " + table.name());
}

Type guard

boolean isBaseIcebergTable(Table t) { return t instanceof HasTableOperations; }

Try / catch

try {
  Table meta = MetadataTableUtils.createMetadataTableInstance(table, type);
} catch (IllegalArgumentException e) {
  // reload base table from catalog
}

Prevention

When it happens

Trigger: Calling MetadataTableUtils.createMetadataTableInstance(table, type) (or loading a metadata table like 'table.files') where the Table is a metadata table itself, a REST/view wrapper, or any implementation not implementing HasTableOperations.

Common situations: Chaining metadata tables (selecting from a metadata table and creating another metadata table over it); using engine adapters that wrap Table objects; mocking Table in tests without operations.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/2ace524abb7b5086. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/MetadataTableUtils.java:42

public class MetadataTableUtils {
  private MetadataTableUtils() {}

  public static boolean hasMetadataTableName(TableIdentifier identifier) {
    return MetadataTableType.from(identifier.name()) != null;
  }

  public static Table createMetadataTableInstance(Table table, MetadataTableType type) {
    if (table instanceof BaseTable) {
      return createMetadataTableInstance(table, metadataTableName(table.name(), type), type);
    } else if (table instanceof HasTableOperations) {
      return createMetadataTableInstance(
          ((HasTableOperations) table).operations(),
          table.name(),
          metadataTableName(table.name(), type),
          type);
    } else {
      throw new IllegalArgumentException(
          String.format(
              "Cannot create metadata table for table %s: "
                  + "table is not a base table or does not have table operations",
              table));
    }
  }

  public static Table createMetadataTableInstance(
      TableOperations ops, String baseTableName, String metadataTableName, MetadataTableType type) {
    Table baseTable = new BaseTable(ops, baseTableName);
    return createMetadataTableInstance(baseTable, metadataTableName, type);
  }

  private static Table createMetadataTableInstance(
      Table baseTable, String metadataTableName, MetadataTableType type) {
    switch (type) {
      case ENTRIES:
        return new ManifestEntriesTable(baseTable, metadataTableName);

View on GitHub (pinned to 86d9c8fc54)