{"record":{"id":"36ec5fe66b50610e","repo":"mlflow/mlflow","slug":"move-aborted-merging-workspaces-would-create-dupl","errorCode":null,"errorMessage":"Move aborted: merging workspaces would create duplicate {resource_description}. Resolve the following conflicts by renaming the affected resources (restore deleted ones first) or permanently deleting them, then retry: {formatted_conflicts}","messagePattern":"Move aborted: merging workspaces would create duplicate (.+?)\\. Resolve the following conflicts by renaming the affected resources \\(restore deleted ones first\\) or permanently deleting them, then retry: (.+?)","errorType":"console","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"mlflow/store/db/workspace_migration.py","lineNumber":89,"sourceCode":"        sa.select(*group_columns).group_by(*group_columns).having(sa.func.count() > 1).subquery()\n    )\n    join_conditions = [table.c[column] == conflict_keys.c[column] for column in columns]\n    extra_columns = []\n    if table_name == \"experiments\" and \"experiment_id\" in table.c:\n        extra_columns.append(table.c.experiment_id)\n    conflict_rows_stmt = (\n        sa\n        .select(*group_columns, table.c.workspace, *extra_columns)\n        .select_from(table.join(conflict_keys, sa.and_(*join_conditions)))\n        .order_by(*group_columns, table.c.workspace, *extra_columns)\n    )\n    if conflicts := conn.execute(conflict_rows_stmt).fetchall():\n        formatted_conflicts = _format_conflicts(\n            conflicts,\n            (*columns, \"workspace\", *(column.name for column in extra_columns)),\n            max_rows=None if verbose else 5,\n        )\n        raise RuntimeError(\n            \"Move aborted: merging workspaces would create duplicate \"\n            f\"{resource_description}. Resolve the following conflicts by renaming the affected \"\n            \"resources (restore deleted ones first) or permanently deleting them, then retry: \"\n            f\"{formatted_conflicts}\"\n        )\n\n\ndef migrate_to_default_workspace(\n    engine: sa.Engine,\n    dry_run: bool = False,\n    *,\n    verbose: bool = False,\n) -> dict[str, int]:\n    \"\"\"\n    Move all workspace-scoped resources into the default workspace.\n    Returns a mapping of table name -> number of rows moved (or that would be moved in dry-run).\n    When verbose is True, conflict lists are not truncated.\n    \"\"\"","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/mlflow/mlflow/blob/6a27f2decc0b76eb1b54af31849784addb357dbc/mlflow/store/db/workspace_migration.py#L71-L107","documentation":"During migration of a legacy (no-workspace) database into the default workspace, _assert_no_workspace_conflicts checks whether moving rows into the target workspace would violate uniqueness (same name/experiment_id etc. already existing in the default workspace, including soft-deleted rows). If duplicates would result, it aborts with a RuntimeError listing the conflicting rows so nothing is silently merged.","triggerScenarios":"Running `mlflow db migrate-workspaces` (migrate_to_default_workspace) on a DB where the default workspace already contains resources whose names/keys collide with ones in the legacy root: duplicate experiment names, registered model names, or prompt names, including soft-deleted rows.","commonSituations":"Re-running migration after a partial move, having created new experiments/models in the default workspace before migrating legacy data, soft-deleted resources still occupying names.","solutions":["Read formatted_conflicts in the message and rename the offending resources in one side (restore soft-deleted ones first, rename, or delete them permanently), then re-run the migration","Permanently delete duplicate/obsolete rows so names are free","Use --verbose to see all conflicting rows instead of the first 5","Restore deleted resources listed in conflicts, rename or purge them, then retry"],"exampleFix":"# before: duplicate experiment 'bert-prod' exists in both places\nmlflow db migrate-workspaces --backend-store-uri sqlite:///mlflow.db\n# RuntimeError listing conflicts\n# after: rename the legacy experiment first\nmlflow experiments rename --experiment-name bert-prod --new-name bert-prod-legacy\nmlflow db migrate-workspaces --backend-store-uri sqlite:///mlflow.db","handlingStrategy":"validation","validationCode":"# Pre-check for name collisions before migrating\nfrom mlflow.tracking import MlflowClient\nc = MlflowClient()\nexisting = {e.name for e in c.search_experiments(view_type=mlflow.entities.ViewType.ALL)}\nlegacy_names = {'exp-a', 'exp-b'}  # names present in the pre-migration DB\nconflicts = existing & legacy_names\nif conflicts:\n    raise SystemExit(f'Rename or delete duplicates first: {conflicts}')","typeGuard":null,"tryCatchPattern":"import subprocess\nr = subprocess.run(['mlflow', 'db', 'migrate-workspaces', ...], capture_output=True, text=True)\nif r.returncode != 0 and 'Move aborted: merging workspaces would create duplicate' in r.stderr:\n    resolve_conflicts_from_report(r.stderr)\n    subprocess.run([...], check=True)  # retry","preventionTips":["Run migration on a fresh backup/clone so the default workspace is empty","Restore and permanently purge soft-deleted duplicates before migrating","Use --verbose to see the full conflict list","Do a dry run against a staging copy of the DB first"],"tags":["database","migration","workspace","conflict"],"backgroundTag":"duplicate-resource-conflict","analyzedSha":"6a27f2decc0b76eb1b54af31849784addb357dbc","analyzedAt":"2026-08-29T20:54:51.419Z","schemaVersion":2},"datasetVersion":"2026-08-29T22:17:34.462Z"}