langgenius/dify · error · ValueError
Unsupported legacy workspace role: {legacy_role}
Error message
Unsupported legacy workspace role: {legacy_role} What it means
ValueError raised by _resolve_builtin_role_id when the supplied legacy_role string is not a key in _LEGACY_ROLE_TO_BUILTIN_TAG (owner/admin/editor/normal/dataset_operator). This guards against unknown role values before attempting tenant-scoped lookup.
Source
Thrown at api/commands/rbac.py:64
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(
tenant_id: str | None,
*,
db_batch_size: int,
api_batch_size: int,
) -> Iterator[tuple[str, str, list[tuple[str, str]]]]:
"""Yield legacy member roles in tenant-scoped API-sized batches.
Rows are projected to primitive values and streamed from the database, so
the command never materializes every TenantAccountJoin ORM object. The
iterator only keeps one tenant's API-sized batches in memory while it
finds that tenant's owner account.
"""
with session_factory.create_session() as session:View on GitHub (pinned to ef8544b173)
Solutions
- Inspect the actual legacy_role value being passed; query TenantAccountJoin.role distinct values for the tenant.
- If the role is legitimate, add its mapping to _LEGACY_ROLE_TO_BUILTIN_TAG with the correct builtin tag.
- If the role is corrupt data, clean the TenantAccountJoin rows or filter them out before migration.
- Add a regression test covering any new TenantAccountRole enum member.
Example fix
# before
_LEGACY_ROLE_TO_BUILTIN_TAG = {
TenantAccountRole.OWNER.value: "owner",
TenantAccountRole.ADMIN.value: "admin",
}
# legacy_role="dataset_operator" -> raises
# after
_LEGACY_ROLE_TO_BUILTIN_TAG = {
TenantAccountRole.OWNER.value: "owner",
TenantAccountRole.ADMIN.value: "admin",
TenantAccountRole.DATASET_OPERATOR.value: "dataset_operator",
} Defensive patterns
Strategy: type-guard
Validate before calling
def is_supported_legacy_role(role: str) -> bool:
return role in _LEGACY_ROLE_TO_BUILTIN_TAG Type guard
def is_supported_legacy_role(role: str) -> bool:
return role in _LEGACY_ROLE_TO_BUILTIN_TAG Try / catch
try:
role_id = _resolve_builtin_role_id(tenant_id, operator_account_id, legacy_role)
except ValueError as exc:
click.echo(f"Skipping unsupported role: {exc}", err=True)
return Prevention
- Keep _LEGACY_ROLE_TO_BUILTIN_TAG updated whenever TenantAccountRole gains a member.
- Add a unit test that asserts every TenantAccountRole member maps.
- Audit distinct TenantAccountJoin.role values before running the migration.
- Reject unknown role strings at ingest, not at migration time.
When it happens
Trigger: Triggered when _resolve_builtin_role_id is called with a legacy_role value not present in the TenantAccountRole enum values mapped in _LEGACY_ROLE_TO_BUILTIN_TAG.
Common situations: A new role was added to TenantAccountRole but not to _LEGACY_ROLE_TO_BUILTIN_TAG, or a corrupt/custom role string exists in TenantAccountJoin.role in the database.
Related errors
- Builtin RBAC role not found for tenant={tenant_id}, legacy_r
- 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/d800f1869f457609.
Report an issue: GitHub.