apache/iceberg · error · java.lang.UnsupportedOperationException

SparkCachedTableCatalog does not support listing tables

Error message

SparkCachedTableCatalog does not support listing tables

What it means

Capability guard in SparkCachedTableCatalog.listTables: this internal catalog only resolves cached table loads (e.g. snapshot/branch/tag time-trap identifiers) and has no table listing. The message names the class; the failure is structural, not data-dependent.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkCachedTableCatalog.java:62

/** An internal table catalog that is capable of loading tables from a cache. */
public class SparkCachedTableCatalog implements TableCatalog, SupportsFunctions {

  private static final String CLASS_NAME = SparkCachedTableCatalog.class.getName();
  private static final Splitter COMMA = Splitter.on(",");
  private static final Pattern AT_TIMESTAMP = Pattern.compile("at_timestamp_(\\d+)");
  private static final Pattern SNAPSHOT_ID = Pattern.compile("snapshot_id_(\\d+)");
  private static final Pattern BRANCH = Pattern.compile("branch_(.*)");
  private static final Pattern TAG = Pattern.compile("tag_(.*)");
  private static final String REWRITE = "rewrite";

  private static final SparkTableCache TABLE_CACHE = SparkTableCache.get();

  private String name = null;

  @Override
  public Identifier[] listTables(String[] namespace) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support listing tables");
  }

  @Override
  public SparkTable loadTable(Identifier ident) throws NoSuchTableException {
    return load(ident);
  }

  @Override
  public SparkTable loadTable(Identifier ident, String version) throws NoSuchTableException {
    SparkTable table = load(ident);
    Preconditions.checkArgument(
        table.snapshotId() == null, "Cannot time travel based on both table identifier and AS OF");
    return table.copyWithSnapshotId(Long.parseLong(version));
  }

  @Override
  public SparkTable loadTable(Identifier ident, long timestampMicros) throws NoSuchTableException {
    SparkTable table = load(ident);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. List tables in the underlying real catalog (spark_catalog or the Iceberg catalog) instead
  2. Avoid invoking listTables on the cached-table catalog; cache lookups go through loadTable only
  3. Guard catalog-listing tooling to skip non-listable catalogs

Example fix

// before
catalogManager.catalog("spark_catalog_cached").asTableCatalog().listTables(ns);
// after
TableCatalog real = catalogManager.catalog("spark_catalog").asTableCatalog();
Identifier[] tables = real.listTables(ns);
Defensive patterns

Strategy: try-catch

Validate before calling

if (catalog instanceof SparkCachedTableCatalog) { /* skip listing, use real catalog */ }

Type guard

boolean isListable(Catalog catalog) { return !(catalog instanceof SparkCachedTableCatalog); }

Try / catch

try { return catalog.listTables(namespace); } catch (UnsupportedOperationException e) { return realCatalog.listTables(namespace); }

Prevention

When it happens

Trigger: Calling SHOW TABLES / listTables against a namespace in the SparkCachedTableCatalog (the catalog used for cached tables, named like spark_catalog_cached or accessed through cached table identifiers).

Common situations: Exploring catalogs in a SQL client and listing all namespaces/tables; tools that enumerate catalog contents encounter this read-only cache catalog.

Related errors


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