{"record":{"id":"e1344eba73303d91","repo":"langgenius/dify","slug":"no-tenants-found","errorCode":null,"errorMessage":"No tenants found.","messagePattern":"No tenants found\\.","errorType":"console","errorClass":"MigrationDataError","httpStatus":null,"severity":"error","filePath":"api/commands/data_migration.py","lineNumber":310,"sourceCode":"    if id_strategy is None and conflict_strategy is None and create_app_api_token_on_import is None:\n        return None\n    return ImportOptions.from_mapping(\n        {\n            \"id_strategy\": id_strategy or package_options.id_strategy,\n            \"conflict_strategy\": conflict_strategy or package_options.conflict_strategy,\n            \"create_app_api_token_on_import\": (\n                create_app_api_token_on_import\n                if create_app_api_token_on_import is not None\n                else package_options.create_app_api_token_on_import\n            ),\n        }\n    )\n\n\ndef _prompt_source_tenant() -> Tenant:\n    tenants = list(db.session.scalars(sa.select(Tenant).order_by(Tenant.name.asc())).all())\n    if not tenants:\n        raise MigrationDataError(\"No tenants found.\")\n\n    _print_wizard_step(\"Source Tenant\")\n    click.echo(\"Source tenants:\")\n    for index, tenant in enumerate(tenants, 1):\n        click.echo(f\"{index}. {tenant.name} ({tenant.id})\")\n\n    tenant_index = click.prompt(\"Select one source tenant by number\", type=int, default=1, show_default=True)\n    if tenant_index < 1 or tenant_index > len(tenants):\n        raise click.ClickException(f\"Selection index out of range: {tenant_index}\")\n    return tenants[tenant_index - 1]\n\n\ndef _eligible_apps_for_tenant(tenant_id: str) -> list[App]:\n    return list(\n        db.session.scalars(\n            sa.select(App)\n            .where(App.tenant_id == tenant_id, App.mode.in_(SUPPORTED_WIZARD_APP_MODES))\n            .order_by(App.name.asc())","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/commands/data_migration.py#L292-L328","documentation":"MigrationDataError raised by _prompt_source_tenant when the database query for tenants returns zero rows. The export wizard cannot proceed without a source tenant to select, so it aborts before prompting. This is surfaced via click.ClickException by the wizard's outer handler.","triggerScenarios":"Triggered when `sa.select(Tenant)` against the configured database returns an empty list - i.e. the Dify instance has no tenants initialized.","commonSituations":"Running the migration wizard against a fresh/uninitialized database, against the wrong database (wrong DATABASE_URI), or against a schema where the tenants table is empty (e.g. a test fixture DB).","solutions":["Verify DATABASE_URI points at the intended Dify database and that the tenants table has rows.","Run `SELECT count(*) FROM tenants;` to confirm data exists.","If the DB is genuinely empty, initialize the workspace first through normal onboarding before migrating.","Ensure the API worker running the command has the same DB config as the running instance."],"exampleFix":"# before - pointing at empty DB\nDATABASE_URI=postgresql://user:pass@host/empty_db\n\n# after\nDATABASE_URI=postgresql://user:pass@host/dify_prod","handlingStrategy":"validation","validationCode":"from sqlalchemy import select\nfrom models import Tenant\n\ndef tenant_count(session) -> int:\n    return session.scalar(select(func.count()).select_from(Tenant)) or 0\n\n# preflight\nif tenant_count(session) == 0:\n    raise SystemExit(\"No tenants in DB; initialize the workspace first\")","typeGuard":"def has_tenants(session) -> bool:\n    return session.scalars(select(Tenant).limit(1)).first() is not None","tryCatchPattern":"try:\n    tenant = _prompt_source_tenant()\nexcept MigrationDataError as exc:\n    click.echo(str(exc), err=True)\n    raise click.Abort()","preventionTips":["Confirm DATABASE_URI points at the populated database before running the wizard.","Run `SELECT count(*) FROM tenants;` as a preflight check.","Ensure the API worker and CLI share the same DB config.","Initialize the workspace through normal onboarding before migrating from an empty DB."],"tags":["backend","cli","data-migration","database","tenant","empty-state"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}