langgenius/dify · error · MigrationDataError
No tenants found.
Error message
No tenants found.
What it means
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.
Source
Thrown at api/commands/data_migration.py:310
if id_strategy is None and conflict_strategy is None and create_app_api_token_on_import is None:
return None
return ImportOptions.from_mapping(
{
"id_strategy": id_strategy or package_options.id_strategy,
"conflict_strategy": conflict_strategy or package_options.conflict_strategy,
"create_app_api_token_on_import": (
create_app_api_token_on_import
if create_app_api_token_on_import is not None
else package_options.create_app_api_token_on_import
),
}
)
def _prompt_source_tenant() -> Tenant:
tenants = list(db.session.scalars(sa.select(Tenant).order_by(Tenant.name.asc())).all())
if not tenants:
raise MigrationDataError("No tenants found.")
_print_wizard_step("Source Tenant")
click.echo("Source tenants:")
for index, tenant in enumerate(tenants, 1):
click.echo(f"{index}. {tenant.name} ({tenant.id})")
tenant_index = click.prompt("Select one source tenant by number", type=int, default=1, show_default=True)
if tenant_index < 1 or tenant_index > len(tenants):
raise click.ClickException(f"Selection index out of range: {tenant_index}")
return tenants[tenant_index - 1]
def _eligible_apps_for_tenant(tenant_id: str) -> list[App]:
return list(
db.session.scalars(
sa.select(App)
.where(App.tenant_id == tenant_id, App.mode.in_(SUPPORTED_WIZARD_APP_MODES))
.order_by(App.name.asc())View on GitHub (pinned to ef8544b173)
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.
Example fix
# before - pointing at empty DB DATABASE_URI=postgresql://user:pass@host/empty_db # after DATABASE_URI=postgresql://user:pass@host/dify_prod
Defensive patterns
Strategy: validation
Validate before calling
from sqlalchemy import select
from models import Tenant
def tenant_count(session) -> int:
return session.scalar(select(func.count()).select_from(Tenant)) or 0
# preflight
if tenant_count(session) == 0:
raise SystemExit("No tenants in DB; initialize the workspace first") Type guard
def has_tenants(session) -> bool:
return session.scalars(select(Tenant).limit(1)).first() is not None Try / catch
try:
tenant = _prompt_source_tenant()
except MigrationDataError as exc:
click.echo(str(exc), err=True)
raise click.Abort() Prevention
- 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.
When it happens
Trigger: Triggered when `sa.select(Tenant)` against the configured database returns an empty list - i.e. the Dify instance has no tenants initialized.
Common situations: 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).
Related errors
- No workflow or advanced-chat apps found for the selected ten
- {label} JSON is invalid: {exc.msg}
- {label} JSON must be an object.
- AccessDenied
- UsageMissingArg
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/e1344eba73303d91.
Report an issue: GitHub.