{"record":{"id":"897f8dd50a5d2dc4","repo":"apache/superset","slug":"chart-existing-slice-name-r-uuid-config-uuid","errorCode":null,"errorMessage":"Chart {existing.slice_name!r} (uuid {config['uuid']}) was deleted and re-import requires can_write permission to restore it","messagePattern":"Chart (.+?) \\(uuid (.+?)\\) was deleted and re-import requires can_write permission to restore it","errorType":"exception","errorClass":"ImportFailedError","httpStatus":500,"severity":"error","filePath":"superset/commands/chart/importers/v1/utils.py","lineNumber":77,"sourceCode":"\ndef _restore_existing_chart_for_import(\n    existing: Slice,\n    config: dict[str, Any],\n    can_write: bool,\n    user: Any,\n) -> None:\n    # RESTORE path — re-importing a soft-deleted UUID is an implicit\n    # restore-with-update, a distinct operation from overwriting an\n    # alive row, so it is handled in its own branch.\n    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 dashboard\n        # importer reattach to a deleted chart and produce a broken\n        # dashboard.\n        # Name the chart: a dashboard bundle imports many charts, and\n        # without the identity the operator can't tell which of N\n        # charts in the bundle hit the soft-deleted match.\n        raise ImportFailedError(\n            f\"Chart {existing.slice_name!r} (uuid {config['uuid']}) \"\n            f\"was deleted and re-import requires can_write \"\n            f\"permission 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    _ensure_can_edit_existing_chart(\n        existing,\n        user,\n        f\"Chart {existing.slice_name!r} (uuid {config['uuid']}) \"\n        f\"already exists and user doesn't have permissions to restore it\",\n    )\n    # Restore in place (clear ``deleted_at``) rather than\n    # hard-delete-and-replace: a hard delete would cascade to\n    # dashboard_slices and other FK references, breaking the dashboards\n    # that previously embedded this chart.","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/chart/importers/v1/utils.py#L59-L95","documentation":"Raised as ImportFailedError on the RESTORE path of chart import: the bundle's UUID matches a chart row that is soft-deleted, and the importing caller lacks can_write permission, so Superset refuses to implicitly restore the deleted chart. The error names the chart and UUID so operators can identify which item in a multi-chart bundle failed.","triggerScenarios":"Re-importing an export whose chart was deleted in the target workspace, by a user/role without can_write (e.g. ignore_permissions not set, non-privileged importer).","commonSituations":"Restoring a deleted chart from a backup bundle without admin rights; example-loader or background imports running with a restricted principal.","solutions":["Run the import as a user/role with can_write permission (typically Admin) so the soft-deleted chart is restored and updated.","Or purge the soft-deleted row first, then import as a plain create.","Or change the bundle's UUID and import as a brand-new chart."],"exampleFix":"# before: restricted user\nclient.post('/api/v1/chart/import/', files=...)  # ImportFailedError: ...was deleted and re-import requires can_write\n\n# after: import with an account holding can_write, or hard-delete the tombstone row first\nSlice.query.filter_by(uuid=uuid.UUID(bundle_uuid), deleted_at.isnot(None)).delete()","handlingStrategy":"validation","validationCode":"existing = find_existing_for_import(Slice, config['uuid'])\nif existing is not None and existing.deleted_at is not None and not can_write:\n    raise PermissionError('soft-deleted chart requires can_write to restore')","typeGuard":"def is_soft_deleted(chart) -> bool:\n    return chart is not None and chart.deleted_at is not None","tryCatchPattern":"from superset.commands.importers.exceptions import ImportFailedError\ntry:\n    import_chart(...)\nexcept ImportFailedError as ex:\n    if 'requires can_write' in str(ex):\n        escalate_to_admin_import()","preventionTips":["Run restore imports with a can_write principal.","Check for soft-deleted UUID matches before importing."],"tags":["import-export","chart","soft-delete","restore","permissions"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}