apache/iceberg · error · IllegalArgumentException

listNamespaces must be at either ROOT or DATABASE level; got

Error message

listNamespaces must be at either ROOT or DATABASE level; got %s from namespace %s

What it means

SnowflakeCatalog.listNamespaces can only enumerate databases (ROOT scope) or schemas (DATABASE scope). A namespace resolving to SCHEMA or TABLE scope reaches the default branch and throws IllegalArgumentException, because Snowflake has no third namespace level to list.

Source

Thrown at snowflake/src/main/java/org/apache/iceberg/snowflake/SnowflakeCatalog.java:189

  @Override
  public void createNamespace(Namespace namespace, Map<String, String> metadata) {
    throw new UnsupportedOperationException(
        "SnowflakeCatalog does not currently support createNamespace");
  }

  @Override
  public List<Namespace> listNamespaces(Namespace namespace) {
    SnowflakeIdentifier scope = NamespaceHelpers.toSnowflakeIdentifier(namespace);
    List<SnowflakeIdentifier> results;
    switch (scope.type()) {
      case ROOT:
        results = snowflakeClient.listDatabases();
        break;
      case DATABASE:
        results = snowflakeClient.listSchemas(scope);
        break;
      default:
        throw new IllegalArgumentException(
            String.format(
                "listNamespaces must be at either ROOT or DATABASE level; got %s from namespace %s",
                scope, namespace));
    }

    return results.stream().map(NamespaceHelpers::toIcebergNamespace).collect(Collectors.toList());
  }

  @Override
  public Map<String, String> loadNamespaceMetadata(Namespace namespace)
      throws NoSuchNamespaceException {
    SnowflakeIdentifier id = NamespaceHelpers.toSnowflakeIdentifier(namespace);
    boolean namespaceExists;
    switch (id.type()) {
      case DATABASE:
        namespaceExists = snowflakeClient.databaseExists(id);
        break;
      case SCHEMA:

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Only call listNamespaces with Namespace.empty() or a single-level (database) namespace
  2. Treat a two-level namespace as a leaf: stop recursion at schema level
  3. Check namespace.levels().length <= 1 before invoking listNamespaces

Example fix

// before
catalog.listNamespaces(Namespace.of("db", "schema")); // throws
// after
if (namespace.levels().length <= 1) {
  catalog.listNamespaces(namespace);
}
Defensive patterns

Strategy: validation

Validate before calling

if (namespace.levels().length > 1) {
  throw new IllegalArgumentException(
      "listNamespaces supports only ROOT or DATABASE level: " + namespace);
}

Type guard

boolean isListableNamespace(Namespace ns) {
  return ns != null && ns.levels().length <= 1;
}

Try / catch

try {
  catalog.listNamespaces(namespace);
} catch (IllegalArgumentException e) {
  // stop recursion: schema-level namespaces have no children here
}

Prevention

When it happens

Trigger: Calling listNamespaces(Namespace.of("db","schema")) — schema-level listing is not supported; the input namespace must be empty (ROOT) or exactly one level (DATABASE).

Common situations: Generic catalog explorers that recursively list nested namespaces; code ported from Hive/Hadoop catalogs listing children of a schema; tooling iterating all namespace levels.

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/1f6e616e727349dc. Report an issue: GitHub.