langgenius/dify · critical · ValueError
Builtin RBAC role not found for tenant={tenant_id}, legacy_r
Error message
Builtin RBAC role not found for tenant={tenant_id}, legacy_role={legacy_role} What it means
ValueError raised in _resolve_builtin_role_ids when one of the expected builtin RBAC role tags (owner, admin, editor, normal, dataset_operator) is not present among the tenant's global_system_default builtin roles returned by RBACService.Roles.list. Each legacy workspace role maps to an expected builtin tag; if that tag's role id is missing, the migration cannot map members.
Source
Thrown at api/commands/rbac.py:51
identified by runtime ids, so the command must look them up per tenant.
"""
roles = RBACService.Roles.list(
tenant_id=tenant_id,
account_id=operator_account_id,
options=ListOption(page_number=1, results_per_page=100),
).data
role_id_by_tag = {
role.role_tag: role.id
for role in roles
if role.is_builtin and role.category == "global_system_default" and role.role_tag
}
resolved: dict[str, str] = {}
for legacy_role, expected_builtin_tag in _LEGACY_ROLE_TO_BUILTIN_TAG.items():
role_id = role_id_by_tag.get(expected_builtin_tag)
if expected_builtin_tag == "dataset_operator" and not dify_config.DATASET_OPERATOR_ENABLED:
continue
if not role_id:
raise ValueError(f"Builtin RBAC role not found for tenant={tenant_id}, legacy_role={legacy_role}")
resolved[legacy_role] = role_id
return resolved
def _resolve_builtin_role_id(tenant_id: str, operator_account_id: str, legacy_role: str) -> str:
"""Resolve a legacy workspace role to the current tenant's builtin RBAC role id.
The migration replays the old `TenantAccountJoin.role` values onto the
RBAC member-role binding API. Builtin RBAC roles are tenant-scoped and
identified by runtime ids, so the command must look them up per tenant.
"""
if legacy_role not in _LEGACY_ROLE_TO_BUILTIN_TAG:
raise ValueError(f"Unsupported legacy workspace role: {legacy_role}")
return _resolve_builtin_role_ids(tenant_id, operator_account_id)[legacy_role]
def _iter_tenant_member_batches(View on GitHub (pinned to ef8544b173)
Solutions
- Ensure RBAC builtin role seeding ran for this tenant (check the roles API or DB for owner/admin/editor/normal tags).
- Verify the operator account used by the command has permission to list roles for the tenant.
- If DATASET_OPERATOR_ENABLED is false intentionally, confirm the failing role is not dataset_operator (which is expected to be skipped).
- If the tenant has >100 builtin roles, increase the ListOption results_per_page.
Example fix
# before - roles not seeded flask rbac-migrate-member-roles # raises # after - seed builtin roles first flask rbac-seed-builtin-roles && flask rbac-migrate-member-roles
Defensive patterns
Strategy: validation
Validate before calling
def builtin_roles_present(tenant_id, operator_account_id) -> bool:
roles = RBACService.Roles.list(
tenant_id=tenant_id, account_id=operator_account_id,
options=ListOption(page_number=1, results_per_page=100),
).data
tags = {r.role_tag for r in roles if r.is_builtin and r.category == "global_system_default"}
required = set(_LEGACY_ROLE_TO_BUILTIN_TAG.values())
if not dify_config.DATASET_OPERATOR_ENABLED:
required.discard("dataset_operator")
return required.issubset(tags) Type guard
def has_required_builtin_tags(role_tags: set[str]) -> bool:
required = set(_LEGACY_ROLE_TO_BUILTIN_TAG.values())
if not dify_config.DATASET_OPERATOR_ENABLED:
required.discard("dataset_operator")
return required.issubset(role_tags) Try / catch
try:
role_ids = _resolve_builtin_role_ids(tenant_id, operator_account_id)
except ValueError as exc:
click.echo(f"RBAC role catalog incomplete: {exc}", err=True)
raise click.Abort() Prevention
- Run builtin role seeding before member-role migration.
- Verify the operator account can list builtin roles for each tenant.
- If a tenant has >100 builtin roles, increase results_per_page.
- Toggle DATASET_OPERATOR_ENABLED only when consistent with legacy data.
When it happens
Trigger: Triggered when the RBAC roles list for the tenant (page 1, 100 per page) lacks a role whose role_tag equals the expected builtin tag and whose is_builtin is true and category is 'global_system_default'. Also note dataset_operator is skipped when DATASET_OPERATOR_ENABLED is false.
Common situations: The tenant's builtin roles were not seeded (incomplete RBAC initialization), the role catalog changed in a version upgrade, pagination missed roles because there are more than 100 builtin roles, or the operator account lacks permission to list roles.
Related errors
- Unsupported legacy workspace role: {legacy_role}
- Workspace owner not found for tenant={current_tenant_id}
- Unsupported legacy dataset permission: {permission}
- Vector store {vector_type} is not supported.
- {label} JSON is invalid: {exc.msg}
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/cbac398bd726bb17.
Report an issue: GitHub.