{"record":{"id":"d7968a0760a04a45","repo":"langflow-ai/langflow","slug":"system-roles-cannot-be-modified","errorCode":null,"errorMessage":"System roles cannot be modified","messagePattern":"System roles cannot be modified","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/authz_roles.py","lineNumber":171,"sourceCode":"    logger.info(\"Created role %s (id=%s)\", role.name, role.id)\n    return RoleRead.model_validate(role)\n\n\n@router.patch(\"/{role_id}\", response_model=RoleRead)\nasync def update_role(\n    role_id: UUID,\n    payload: RoleUpdate,\n    current_user: CurrentActiveUser,\n    session: DbSession,\n) -> RoleRead:\n    \"\"\"Update fields on a custom role. System roles are read-only.\"\"\"\n    _require_superuser(current_user)\n\n    role = await session.get(AuthzRole, role_id)\n    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                )","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/authz_roles.py#L153-L189","documentation":"Raised by PATCH /api/v1/authz/roles/{role_id} when the target role has is_system=True. System roles (the seeded viewer/developer/admin catalog) are read-only; the route rejects any modification with HTTP 400 'System roles cannot be modified'.","triggerScenarios":"PATCH /api/v1/authz/roles/{id} for one of the three system-seeded roles — attempting to rename it, change permissions, repoint its parent, or clear its description. Any field in RoleUpdate triggers the check.","commonSituations":"Admins trying to tweak the built-in role catalog instead of creating a derived custom role (using parent_role_id to inherit), or provisioning scripts that 'ensure permissions' on every role including system ones.","solutions":["Create a custom role with parent_role_id pointing at the system role and set permissions on the child","Assign the custom role to users instead of mutating the system role","Filter out is_system roles in admin UI edit actions","Make provisioning scripts skip rows where is_system is true"],"exampleFix":"// before\nawait api.patch(`/authz/roles/${devRoleId}`, { permissions: ['flow:deploy'] });\n\n// after\nawait api.post('/authz/roles', { name: 'deployer', parent_role_id: devRoleId, permissions: ['flow:deploy'] });\n// then assign 'deployer' to users","handlingStrategy":"validation","validationCode":"const role = await api.get(`/authz/roles/${id}`);\nif (role.is_system) throw new Error('system roles are read-only; create a child role instead');","typeGuard":"const isModifiableRole = (r: { is_system: boolean }): boolean => !r.is_system;","tryCatchPattern":"catch (e) { if (e.status === 400) offerCreateChildRole(roleId, patch); }","preventionTips":["Model customizations as child roles with parent_role_id inheritance, never edits to system roles","Filter is_system roles out of editable admin UI actions","Provisioning scripts must skip is_system rows"],"tags":["authz","rbac","http-400","roles","system-roles"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}