apache/iceberg · error · NoSuchNamespaceException

Cannot create table %s. Namespace does not exist: %s

Error message

Cannot create table %s. Namespace does not exist: %s

What it means

InMemoryCatalog's table commit path (doCommit in the inner table operator) validates that the table's namespace exists before creating a new table (base == null). Iceberg requires the parent namespace to be created explicitly via createNamespace; it never auto-creates namespaces. If the namespace is missing, NoSuchNamespaceException is thrown and the metadata file already written is effectively abandoned.

Source

Thrown at core/src/main/java/org/apache/iceberg/inmemory/InMemoryCatalog.java:432

    @Override
    public void doRefresh() {
      String latestLocation = tables.get(tableIdentifier);
      if (latestLocation == null) {
        disableRefresh();
      } else {
        refreshFromMetadataLocation(latestLocation);
      }
    }

    @Override
    public void doCommit(TableMetadata base, TableMetadata metadata) {
      String newLocation = writeNewMetadataIfRequired(base == null, metadata);
      String oldLocation = base == null ? null : base.metadataFileLocation();

      synchronized (InMemoryCatalog.this) {
        if (null == base && !namespaceExists(tableIdentifier.namespace())) {
          throw new NoSuchNamespaceException(
              "Cannot create table %s. Namespace does not exist: %s",
              tableIdentifier, tableIdentifier.namespace());
        }

        if (views.containsKey(tableIdentifier)) {
          throw new AlreadyExistsException(
              "View with same name already exists: %s", tableIdentifier);
        }

        tables.compute(
            tableIdentifier,
            (k, existingLocation) -> {
              if (!Objects.equal(existingLocation, oldLocation)) {
                if (null == base) {
                  throw new AlreadyExistsException("Table already exists: %s", tableName());
                }

                if (null == existingLocation) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Call catalog.createNamespace(ident.namespace()) before createTable.
  2. Guard with namespaceExists: if (!catalog.namespaceExists(ns)) catalog.createNamespace(ns).
  3. Use createOrReplace/create if the catalog API offers an auto-create variant for your flow.
  4. Verify the namespace spelling matches what was registered.

Example fix

// before
catalog.createTable(TableIdentifier.of("analytics", "events"), schema);

// after
Namespace ns = Namespace.of("analytics");
if (!catalog.namespaceExists(ns)) {
  catalog.createNamespace(ns);
}
catalog.createTable(TableIdentifier.of("analytics", "events"), schema);
Defensive patterns

Strategy: validation

Validate before calling

Namespace ns = ident.namespace();
if (!catalog.namespaceExists(ns)) {
  catalog.createNamespace(ns);
}

Try / catch

try { catalog.createTable(ident, schema); } catch (NoSuchNamespaceException e) { catalog.createNamespace(ident.namespace()); catalog.createTable(ident, schema); }

Prevention

When it happens

Trigger: Calling catalog.createTable(ident, schema) (or any operation that triggers a first commit) where ident.namespace() was never registered via catalog.createNamespace(...).

Common situations: Forgetting to create namespaces in tests or local in-memory setups; migrating code from catalogs that auto-create namespaces (e.g. some Hadoop setups); typo in namespace name; environment reset that cleared the in-memory catalog between steps.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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