apache/iceberg · error · NamespaceNotEmptyException
%s is not empty: %s
Error message
%s is not empty: %s
What it means
NamespaceNotEmptyException from BigQueryMetastoreClientImpl.delete wrapping the upstream BigQuery error when a dataset cannot be deleted because it still contains tables. The client rethrows with the dataset id plus the original message so the caller knows why the drop failed.
Source
Thrown at bigquery/src/main/java/org/apache/iceberg/gcp/bigquery/BigQueryMetastoreClientImpl.java:219
@Override
public void delete(DatasetReference datasetReference) {
try {
HttpResponse response =
client
.datasets()
.delete(datasetReference.getProjectId(), datasetReference.getDatasetId())
.executeUnparsed();
if (response.getStatusCode() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) {
throw new NoSuchNamespaceException(
"Namespace does not exist: %s", datasetReference.getDatasetId());
}
convertExceptionIfUnsuccessful(response);
} catch (IOException e) {
throw new RuntimeIOException(e);
} catch (NamespaceNotEmptyException e) {
throw new NamespaceNotEmptyException(
"%s is not empty: %s", datasetReference.getDatasetId(), e.getMessage());
}
}
@Override
public boolean setParameters(DatasetReference datasetReference, Map<String, String> parameters) {
Dataset dataset = load(datasetReference);
ExternalCatalogDatasetOptions existingOptions = dataset.getExternalCatalogDatasetOptions();
Map<String, String> existingParameters =
(existingOptions == null || existingOptions.getParameters() == null)
? Maps.newHashMap() // Use HashMap to allow modification below
: Maps.newHashMap(existingOptions.getParameters()); // Copy to compare later
// Calculate what the new parameters would be.
Map<String, String> newParameters = Maps.newHashMap(existingParameters);
newParameters.putAll(parameters);
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Drop all tables first (catalog.listTables then dropTable each) before dropping the namespace
- Use catalog.dropNamespace(ns, true) purge semantics if you intend recursive deletion where supported
- Inspect the dataset in BigQuery console for foreign tables blocking deletion
- Catch NamespaceNotEmptyException in teardown scripts and handle cleanup explicitly
Example fix
// before
catalog.dropNamespace(ns); // throws if dataset has tables
// after
for (TableIdentifier t : catalog.listTables(ns)) {
catalog.dropTable(t);
}
catalog.dropNamespace(ns); Defensive patterns
Strategy: validation
Validate before calling
boolean empty = catalog.listTables(ns).isEmpty(); if (!empty) { /* drop tables first */ } Try / catch
try { catalog.dropNamespace(ns); } catch (NamespaceNotEmptyException e) { /* clean up tables then retry */ } Prevention
- List and drop all tables before dropping the namespace
- Look for non-Iceberg tables left in the dataset
- Decide purge semantics explicitly in teardown scripts
When it happens
Trigger: Calling dropNamespace / client.delete on a dataset that still holds tables (Iceberg or non-Iceberg), where BigQuery refuses datasets.delete and the response surfaces a 'not empty' condition.
Common situations: dropNamespace without purge on a namespace that still has registered tables, leftover non-Iceberg tables inside the dataset, failed earlier table drops leaving orphans.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot drop namespace %s because it still contains Iceberg t
- Cannot drop namespace %s because it still contains non-Icebe
- Namespace does not exist: %s
- %s
- Namespace already exists: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/488c68ca077c0492.
Report an issue: GitHub.