apache/superset · error · ImportFailedError
Dataset {existing.table_name!r} (uuid {config['uuid']}) alre
Error message
Dataset {existing.table_name!r} (uuid {config['uuid']}) already exists and user doesn't have permissions to overwrite it What it means
On the overwrite path (UUID matches a live dataset), if overwrite=True and can_write hold but the current user is neither an editor/owner of that dataset nor an admin, ImportFailedError is raised. It blocks users who can import in general from clobbering datasets they do not own.
Source
Thrown at superset/commands/dataset/importers/v1/utils.py:347
# ``MultipleResultsFound`` fallback. Without the rollback, an
# ambiguous import would leave the dataset half-restored
# (``deleted_at = None`` but upload contents unapplied).
original_deleted_at = existing.deleted_at
existing.restore()
db.session.flush()
is_soft_deleted_match = True
config["id"] = existing.id
else:
# OVERWRITE path — existing alive row. Without ``overwrite`` or
# write permission, return it unchanged (the pre-soft-delete
# overwrite-without-permission behaviour).
if not overwrite or not can_write:
return existing
if user and (
not security_manager.is_editor(existing)
and not security_manager.is_admin()
):
raise ImportFailedError(
f"Dataset {existing.table_name!r} (uuid {config['uuid']}) "
"already exists and user doesn't have permissions to "
"overwrite it"
)
# Mirror the REST update path's uniqueness contract: the uploaded
# config may rename this dataset onto the physical identity of a
# soft-deleted twin. ``import_from_dict``'s lookup cannot see the
# hidden row (visibility filter), so without this check the
# update would land cleanly and the live row would silently squat
# the trash row's identity — permanently 422-blocking its
# restore. ``validate_update_uniqueness`` bypasses the filter by
# design, so hidden twins block here exactly as they block
# ``UpdateDatasetCommand``.
overwrite_identity = Table(
config.get("table_name") or existing.table_name,
config.get("schema", existing.schema),
config.get("catalog", existing.catalog),
)View on GitHub (pinned to f4587218dd)
Solutions
- Add the importing user (or service account) as an owner of the target dataset, then retry
- Run the import as an admin
- Import without overwrite if the existing dataset should stay untouched
Defensive patterns
Strategy: try-catch
Validate before calling
from superset import security_manager
existing = find_existing_for_import(SqlaTable, config['uuid'])
if existing is not None and existing.deleted_at is None and overwrite:
user = security_manager.get_current_user()
if user and not (security_manager.is_editor(existing) or security_manager.is_admin()):
raise PermissionError('importing user must own the target dataset to overwrite it') Try / catch
from superset.commands.exceptions import ImportFailedError
try:
import_dataset(config, overwrite=True)
except ImportFailedError as ex:
if "doesn't have permissions to overwrite it" in str(ex):
# add user as owner of the dataset, or import without overwrite; no blind retry
... Prevention
- Add CI service accounts as owners of datasets they re-import
- Import without overwrite when you only need existence
- Scope bundles per team so UUIDs don't cross ownership boundaries
When it happens
Trigger: POST /api/v1/dataset/import with overwrite=true where the UUID matches a live dataset owned by others and the importing user is not an owner/editor/admin.
Common situations: Shared workspaces: one team imports a bundle that happens to carry another team's dataset UUID; CI re-imports under a service account that lacks ownership of pre-existing datasets.
Related errors
- Dataset {existing.table_name!r} (uuid {config['uuid']}) alre
- Dataset {existing.table_name!r} (uuid {config['uuid']}) was
- Dataset {existing.table_name!r} (uuid {config['uuid']}) cann
- Dataset doesn't exist and user doesn't have permission to cr
- You don't have access to this dataset.
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/5003f9e55af90856.
Report an issue: GitHub.