apache/superset · error · DatasetLogicalDuplicateError

Dataset cannot be restored because another active dataset al

Error message

Dataset cannot be restored because another active dataset already references the same physical table (same database, catalog, schema, and table name). Delete the duplicate or rename the table before restoring.

What it means

DatasetLogicalDuplicateError is raised by DatasetRestoreCommand.validate() when DatasetDAO.has_active_logical_duplicate(model) is true — i.e. while this dataset was soft-deleted, another active dataset row claimed the same physical table (same database, catalog, schema, table_name). Because DB-level uniqueness enforcement is inconsistent across schema builds, the command refuses the restore to return a clean 422 instead of an IntegrityError or a silent twin dataset.

Source

Thrown at superset/commands/dataset/restore.py:59

    than relying on the DB, which would either reject with an opaque
    IntegrityError or — where no constraint applies — silently allow two
    active datasets pointing at the same physical table.
    """

    dao = DatasetDAO
    not_found_exc = DatasetNotFoundError
    forbidden_exc = DatasetForbiddenError
    restore_failed_exc = DatasetRestoreFailedError

    def validate(self) -> SqlaTable:  # type: ignore[override]
        model = super().validate()
        # DB-level uniqueness enforcement is inconsistent across schema
        # builds (see class docstring), so restoring must refuse here if
        # another active dataset claimed the same physical table while this
        # one was soft-deleted — a clean 422 instead of an IntegrityError
        # or a silent twin.
        if DatasetDAO.has_active_logical_duplicate(model):
            raise DatasetLogicalDuplicateError()
        return model

View on GitHub (pinned to f4587218dd)

Solutions

  1. Delete (or hard-delete/purge) the newer duplicate dataset that now references the same physical table, then restore the soft-deleted one.
  2. Or rename the physical table (or point the duplicate at a different catalog/schema) so the (database, catalog, schema, table_name) tuple no longer collides.
  3. If the duplicate itself is the keeper, simply purge the soft-deleted row instead of restoring it.
  4. After resolving, retry the restore; verify uniqueness by listing datasets filtered by table_name.

Example fix

# before
PUT /api/v1/dataset/42/restore
# 422 ... another active dataset already references the same physical table

# after
# 1) find the twin
GET /api/v1/dataset?q=(r:1,table_name:eq:my_table)
# 2) delete the active duplicate (say id 99)
DELETE /api/v1/dataset/99
# 3) restore
PUT /api/v1/dataset/42/restore
Defensive patterns

Strategy: validation

Validate before calling

from superset.daos.dataset import DatasetDAO

model = DatasetDAO.find_by_id(model_id)
if model is not None and DatasetDAO.has_active_logical_duplicate(model):
    raise SystemExit("resolve duplicate active dataset before restore")

Try / catch

try:
    DatasetRestoreCommand(user, model_id).run()
except DatasetLogicalDuplicateError as ex:
    # message names the collision; delete/rename the twin, then retry once

Prevention

When it happens

Trigger: Restoring a soft-deleted dataset (PUT /api/v1/dataset/{id}/restore or trash-restore UI) after someone re-created a dataset pointing at the identical physical table in the meantime. Also when two environments' data was merged, or a duplicate was created before the uniqueness constraint existed.

Common situations: Delete-then-recreate workflows: user deleted a dataset, re-added the same table as a new dataset, then later tries to restore the original from the trash. Restoring old backups/snapshots into a database where the table is already mapped.

Related errors


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