apache/iceberg · error · IllegalArgumentException

%s does not have a metadata file location

Error message

%s does not have a metadata file location

What it means

TableUtil.metadataFileLocation(Table) returns the location of the current metadata JSON file, but only when the table's operations are accessible (HasTableOperations or BaseMetadataTable). For other Table implementations there is no metadata file to report, so IllegalArgumentException is thrown with the table class's simple name.

Source

Thrown at core/src/main/java/org/apache/iceberg/TableUtil.java:58

      throw new IllegalArgumentException(
          String.format("%s does not have a format version", table.getClass().getSimpleName()));
    }
  }

  /** Returns the metadata file location of the given table */
  public static String metadataFileLocation(Table table) {
    Preconditions.checkArgument(null != table, "Invalid table: null");

    if (table instanceof SerializableTable) {
      SerializableTable serializableTable = (SerializableTable) table;
      return serializableTable.metadataFileLocation();
    } else if (table instanceof HasTableOperations) {
      HasTableOperations ops = (HasTableOperations) table;
      return ops.operations().current().metadataFileLocation();
    } else if (table instanceof BaseMetadataTable) {
      return ((BaseMetadataTable) table).table().operations().current().metadataFileLocation();
    } else {
      throw new IllegalArgumentException(
          String.format(
              "%s does not have a metadata file location", table.getClass().getSimpleName()));
    }
  }

  public static boolean supportsRowLineage(Table table) {
    Preconditions.checkArgument(null != table, "Invalid table: null");
    if (table instanceof BaseMetadataTable) {
      return false;
    }

    return formatVersion(table) >= TableMetadata.MIN_FORMAT_VERSION_ROW_LINEAGE;
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Load the table through a catalog so it is a BaseTable with HasTableOperations
  2. For static tables, use the metadata location string you created the table with instead
  3. Unwrap BaseMetadataTable instances before querying the location
  4. Implement HasTableOperations in custom Table wrappers that must report a metadata location

Example fix

// before
String loc = TableUtil.metadataFileLocation(customWrapper); // throws
// after
String loc = TableUtil.metadataFileLocation(catalog.loadTable(id));
Defensive patterns

Strategy: type-guard

Validate before calling

boolean hasMetadataLocation(Table t) {
  return t instanceof BaseMetadataTable || t.operations() instanceof HasTableOperations;
}

Type guard

String safeMetadataFileLocation(Table t) {
  if (t instanceof BaseMetadataTable) {
    return ((BaseMetadataTable) t).table().operations().current().metadataFileLocation();
  }
  return (t.operations() instanceof HasTableOperations)
      ? ((HasTableOperations) t).operations().current().metadataFileLocation()
      : null;
}

Try / catch

try { loc = TableUtil.metadataFileLocation(table); }
catch (IllegalArgumentException e) { loc = null; /* table impl has no metadata file */ }

Prevention

When it happens

Trigger: TableUtil.metadataFileLocation(table) on a Table that is neither HasTableOperations nor BaseMetadataTable — e.g. StaticTableOperations-backed StaticTable (whose metadata location isn't surfaced this way), custom decorators, or mocks.

Common situations: Tooling that prints/exports the current metadata file path applied to static or wrapped tables; audit/debug utilities assuming all Table handles expose operations; engine adapters passing wrapper objects.

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


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