{"record":{"id":"9163af9ee7102ae5","repo":"langflow-ai/langflow","slug":"a-role-cannot-be-its-own-parent","errorCode":null,"errorMessage":"A role cannot be its own parent","messagePattern":"A role cannot be its own parent","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/authz_roles.py","lineNumber":186,"sourceCode":"    if role is None:\n        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=\"Role not found\")\n    if role.is_system:\n        raise HTTPException(\n            status_code=status.HTTP_400_BAD_REQUEST,\n            detail=\"System roles cannot be modified\",\n        )\n\n    # Use presence checks (model_fields_set) rather than ``is not None`` so PATCH\n    # can clear nullable fields. An explicit ``\"description\": null`` in the body\n    # marks the field as set and assigns None; omitting it leaves the row alone.\n    fields_set = payload.model_fields_set\n\n    if \"parent_role_id\" in fields_set:\n        if payload.parent_role_id is None:\n            role.parent_role_id = None\n        else:\n            if payload.parent_role_id == role.id:\n                raise HTTPException(\n                    status_code=status.HTTP_400_BAD_REQUEST,\n                    detail=\"A role cannot be its own parent\",\n                )\n            parent = await session.get(AuthzRole, payload.parent_role_id)\n            if parent is None:\n                raise HTTPException(\n                    status_code=status.HTTP_400_BAD_REQUEST,\n                    detail=\"parent_role_id does not reference an existing role\",\n                )\n            if await _detect_parent_cycle(session, role_id=role.id, proposed_parent_id=payload.parent_role_id):\n                raise HTTPException(\n                    status_code=status.HTTP_400_BAD_REQUEST,\n                    detail=\"Setting this parent would create a role hierarchy cycle\",\n                )\n            role.parent_role_id = payload.parent_role_id\n\n    if \"description\" in fields_set:\n        # description is nullable on the DB side — None is a legitimate clear.","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/authz_roles.py#L168-L204","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Exclude the role being edited from its own parent dropdown options","In scripts, assert parentId !== roleId before PATCH","If cloning a role, leave parent_role_id null or point it at the true parent, never the new/existing row id"],"exampleFix":"// before\nawait api.patch(`/authz/roles/${id}`, { parent_role_id: id });\n\n// after\nif (parentId === id) throw new Error('role cannot be its own parent');\nawait api.patch(`/authz/roles/${id}`, { parent_role_id: parentId });","handlingStrategy":"type-guard","validationCode":"if (parentRoleId === roleId) throw new Error('role cannot be its own parent');","typeGuard":"const isValidParent = (parentId: string | null, selfId: string): boolean =>\n  parentId === null || parentId !== selfId;","tryCatchPattern":null,"preventionTips":["Exclude the edited role from its own parent dropdown","Assert parentId !== roleId in scripts before PATCH","When cloning roles, leave parent_role_id null"],"tags":["authz","rbac","http-400","roles","hierarchy","validation"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}