langflow-ai/langflow · warning · HTTPException

System roles cannot be modified

Error message

System roles cannot be modified

What it means

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'.

Source

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

    logger.info("Created role %s (id=%s)", role.name, role.id)
    return RoleRead.model_validate(role)


@router.patch("/{role_id}", response_model=RoleRead)
async def update_role(
    role_id: UUID,
    payload: RoleUpdate,
    current_user: CurrentActiveUser,
    session: DbSession,
) -> RoleRead:
    """Update fields on a custom role. System roles are read-only."""
    _require_superuser(current_user)

    role = await session.get(AuthzRole, role_id)
    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",
                )

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Create a custom role with parent_role_id pointing at the system role and set permissions on the child
  2. Assign the custom role to users instead of mutating the system role
  3. Filter out is_system roles in admin UI edit actions
  4. Make provisioning scripts skip rows where is_system is true

Example fix

// before
await api.patch(`/authz/roles/${devRoleId}`, { permissions: ['flow:deploy'] });

// after
await api.post('/authz/roles', { name: 'deployer', parent_role_id: devRoleId, permissions: ['flow:deploy'] });
// then assign 'deployer' to users
Defensive patterns

Strategy: validation

Validate before calling

const role = await api.get(`/authz/roles/${id}`);
if (role.is_system) throw new Error('system roles are read-only; create a child role instead');

Type guard

const isModifiableRole = (r: { is_system: boolean }): boolean => !r.is_system;

Try / catch

catch (e) { if (e.status === 400) offerCreateChildRole(roleId, patch); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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