langflow-ai/langflow · warning · HTTPException

A role cannot be its own parent

Error message

A role cannot be its own parent

What it means

Raised by PATCH /api/v1/authz/roles/{role_id} when parent_role_id in the payload equals the role's own id. Self-parenting is rejected with HTTP 400 before any cycle walk, as the trivial cycle case.

Source

Thrown at src/backend/base/langflow/api/v1/authz_roles.py:186

    if role is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Role not found")
    if role.is_system:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="System roles cannot be modified",
        )

    # Use presence checks (model_fields_set) rather than ``is not None`` so PATCH
    # can clear nullable fields. An explicit ``"description": null`` in the body
    # marks the field as set and assigns None; omitting it leaves the row alone.
    fields_set = payload.model_fields_set

    if "parent_role_id" in fields_set:
        if payload.parent_role_id is None:
            role.parent_role_id = None
        else:
            if payload.parent_role_id == role.id:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="A role cannot be its own parent",
                )
            parent = await session.get(AuthzRole, payload.parent_role_id)
            if parent is None:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="parent_role_id does not reference an existing role",
                )
            if await _detect_parent_cycle(session, role_id=role.id, proposed_parent_id=payload.parent_role_id):
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="Setting this parent would create a role hierarchy cycle",
                )
            role.parent_role_id = payload.parent_role_id

    if "description" in fields_set:
        # description is nullable on the DB side — None is a legitimate clear.

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Exclude the role being edited from its own parent dropdown options
  2. In scripts, assert parentId !== roleId before PATCH
  3. If cloning a role, leave parent_role_id null or point it at the true parent, never the new/existing row id

Example fix

// before
await api.patch(`/authz/roles/${id}`, { parent_role_id: id });

// after
if (parentId === id) throw new Error('role cannot be its own parent');
await api.patch(`/authz/roles/${id}`, { parent_role_id: parentId });
Defensive patterns

Strategy: type-guard

Validate before calling

if (parentRoleId === roleId) throw new Error('role cannot be its own parent');

Type guard

const isValidParent = (parentId: string | null, selfId: string): boolean =>
  parentId === null || parentId !== selfId;

Prevention

When it happens

Trigger: PATCH {"parent_role_id": "<same-uuid-as-path>"} — typically a form bug where the parent dropdown's selected value defaults to the role being edited.

Common situations: Admin UI edit forms that pre-select the current role in the parent picker, or scripts that copy the role row and reuse its id for parent_role_id when cloning.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/9163af9ee7102ae5. Report an issue: GitHub.