apache/superset · error · ImportFailedError

Dataset {existing.table_name!r} (uuid {config['uuid']}) matc

Error message

Dataset {existing.table_name!r} (uuid {config['uuid']}) matches more than one existing row, so the restore-and-update cannot pick a target. Resolve the duplicate rows manually before retrying.

What it means

When import_from_dict raises MultipleResultsFound for the dataset itself (legacy exports imported without schemas can collide with later schema'd rows) and the current import was a soft-deleted restore, the code rolls back the deleted_at clear (restoring the original trash timestamp) and raises ImportFailedError: the restore-and-update cannot pick which duplicate row to target, so the operator must deduplicate first. This differs from the live-overwrite path, which keeps the legacy contract of returning the existing row.

Source

Thrown at superset/commands/dataset/importers/v1/utils.py:485

        # fail because the UUID match will try to update `examples.NULL.users` to
        # `examples.public.users`, resulting in a conflict.
        #
        # In the soft-deleted-restore case we cannot silently return
        # the unmodified row: ``existing.deleted_at`` was already
        # cleared above and the operator expects a restore-with-update.
        # Returning the row without applying the upload would produce a
        # half-restored state. Roll back the ``deleted_at`` clear and
        # raise so the operator can resolve the legacy-NULL-schema
        # ambiguity before re-uploading.
        if is_soft_deleted_match:
            # ``is_soft_deleted_match`` is only ever set inside the
            # ``if existing := ...`` walrus block, so ``existing`` is
            # guaranteed non-None here. The assert pins the invariant
            # for mypy.
            assert existing is not None
            existing.deleted_at = original_deleted_at
            db.session.flush()
            raise ImportFailedError(
                f"Dataset {existing.table_name!r} (uuid {config['uuid']}) "
                "matches more than one existing row, so the restore-and-"
                "update cannot pick a target. Resolve the duplicate rows "
                "manually before retrying."
            ) from ex
        # On the non-soft-deleted overwrite path the legacy contract
        # holds: return the existing row unmodified. Bypasses the
        # visibility filter so a soft-deleted duplicate can be located
        # too — without the bypass the listener would hide the row and
        # the ``.one()`` would raise NoResultFound, masking the
        # original MultipleResultsFound.
        dataset = (
            db.session.query(SqlaTable)
            .execution_options(**{SKIP_VISIBILITY_FILTER_CLASSES: {SqlaTable}})
            .filter_by(uuid=config["uuid"])
            .one()
        )

View on GitHub (pinned to f4587218dd)

Solutions

  1. Deduplicate the matching SqlaTable rows in the metadata DB (keep one, purge the others — take a backup first), then retry the import
  2. If the duplicates are legacy example datasets, removing and re-loading the affected examples can normalize rows
  3. Contact an admin to reconcile rows via SQL on the metadata database
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-flight: count rows matching the import identity
from superset.models.sql_lab import SqlaTable  # adjust import as needed
rows = (
    session.query(SqlaTable)
    .filter(SqlaTable.uuid == config['uuid'])
    .all()
)
if len(rows) > 1:
    raise ValueError(f'{len(rows)} rows share uuid {config["uuid"]} — dedupe the metadata DB first')

Try / catch

from superset.commands.exceptions import ImportFailedError
try:
    import_dataset(config, overwrite=True)
except ImportFailedError as ex:
    if 'matches more than one existing row' in str(ex):
        # stop: needs operator/DBA dedup; the restore was rolled back automatically
        ...

Prevention

When it happens

Trigger: Re-importing an old bundle to restore a soft-deleted dataset while the metadata DB holds more than one row matching the import identity (e.g. legacy NULL-schema rows plus newer schema'd rows sharing uuid/table identity).

Common situations: Instances upgraded from old Superset versions whose example datasets were first imported without schemas and later re-imported with schemas, leaving duplicates; manual DB surgery creating twin rows.

Related errors


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