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

  1. Add the importing user (or service account) as an owner of the target dataset, then retry
  2. Run the import as an admin
  3. 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

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


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/5003f9e55af90856. Report an issue: GitHub.