{"record":{"id":"f02fad3ec3c941d2","repo":"apache/superset","slug":"dataset-existing-table-name-r-uuid-config-uui-f02fad","errorCode":null,"errorMessage":"Dataset {existing.table_name!r} (uuid {config['uuid']}) already exists and user doesn't have permissions to restore it","messagePattern":"Dataset (.+?) \\(uuid (.+?)\\) already exists and user doesn't have permissions to restore it","errorType":"exception","errorClass":"ImportFailedError","httpStatus":500,"severity":"error","filePath":"superset/commands/dataset/importers/v1/utils.py","lineNumber":274,"sourceCode":"            if not can_write:\n                # Case B: don't silently return a soft-deleted row to a caller\n                # without write permission — that would let the importer\n                # reattach charts/dashboards to a deleted dataset and produce\n                # broken charts.\n                raise ImportFailedError(\n                    f\"Dataset {existing.table_name!r} (uuid {config['uuid']}) \"\n                    \"was deleted and re-import requires can_write permission \"\n                    \"to restore it\"\n                )\n            # ``user`` is None on background / example-loader paths; combined\n            # with ``can_write`` (typically from ``ignore_permissions=True``)\n            # the editorship check is intentionally skipped because the caller\n            # already established trust.\n            if user and (\n                not security_manager.is_editor(existing)\n                and not security_manager.is_admin()\n            ):\n                raise ImportFailedError(\n                    f\"Dataset {existing.table_name!r} (uuid {config['uuid']}) \"\n                    \"already exists and user doesn't have permissions to \"\n                    \"restore it\"\n                )\n            # Before clearing ``deleted_at``, refuse if another active dataset\n            # already references the same physical table. Otherwise the\n            # restore would produce two live ``SqlaTable`` rows for one\n            # physical table, breaking the logical-uniqueness contract. The\n            # shared DAO helper relies on the SoftDeleteMixin listener to\n            # consider only active rows, excludes ``existing`` itself via\n            # ``id !=``, and normalizes the catalog the same way create/update\n            # uniqueness does.\n            # Probe the POST-update identity: the uploaded config may rename\n            # table_name/schema/catalog, and the collision that matters is\n            # against the identity the restored row will end up with — not\n            # the stale stored one. Absent keys fall back to the stored\n            # values; explicit nulls are respected.\n            incoming_identity = Table(","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/dataset/importers/v1/utils.py#L256-L292","documentation":"On the restore path of dataset import (soft-deleted UUID match with can_write), if the current user is set and is neither an editor of the existing dataset nor an admin, ImportFailedError is raised. It prevents a privileged-enough-to-write user from restoring (and modifying) a dataset they do not own or co-edit.","triggerScenarios":"A user with can_write imports a bundle matching a soft-deleted dataset that was owned by someone else, with no editorship (owner) grant to this user, and user context present (not a background job).","commonSituations":"Team A deletes a dataset; team B tries to re-import the same export to restore it; ownership was never transferred so B is not an editor.","solutions":["Add the importing user as an owner/editor of the soft-deleted dataset first (admin action), then retry the import","Perform the import as an admin","Have an admin restore the dataset via the REST delete-restore endpoint instead of re-import"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"from superset import security_manager\n# before restoring via import, confirm editorship\nexisting = find_existing_for_import(SqlaTable, config['uuid'])\nif existing is not None and existing.deleted_at is not None:\n    user = security_manager.get_current_user()\n    if user and not (security_manager.is_editor(existing) or security_manager.is_admin()):\n        raise PermissionError('ask an owner/admin to perform this import')","typeGuard":null,"tryCatchPattern":"from superset.commands.exceptions import ImportFailedError\ntry:\n    import_dataset(config, overwrite=True)\nexcept ImportFailedError as ex:\n    if \"doesn't have permissions to restore it\" in str(ex):\n        # request ownership on the soft-deleted dataset or import as admin\n        ...","preventionTips":["Transfer ownership when datasets change teams","Import as admin for restore workflows","Keep owners list current on shared datasets"],"tags":["dataset-import","permissions","ownership","soft-delete","superset"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}