langflow-ai/langflow · warning · HTTPException

Role with name {payload.name!r} already exists

Error message

Role with name {payload.name!r} already exists

What it means

Raised by POST /api/v1/authz/roles when commit hits an IntegrityError on the unique role name — a role with the same name already exists. The route rolls back and returns HTTP 409 with the conflicting name embedded in the detail.

Source

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

            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="parent_role_id does not reference an existing role",
            )

    role = AuthzRole(
        name=payload.name,
        description=payload.description,
        is_system=False,
        permissions=list(payload.permissions),
        parent_role_id=payload.parent_role_id,
        created_by=current_user.id,
    )
    session.add(role)
    try:
        await session.commit()
    except IntegrityError as exc:
        await session.rollback()
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Role with name {payload.name!r} already exists",
        ) from exc
    await session.refresh(role)
    await safe_invalidate_all(get_authorization_service(), op="role:create")
    await audit_decision(
        user_id=current_user.id,
        action="role:create",
        obj=f"role:{role.id}",
        result="allow",
        details={
            "role_name": role.name,
            "permissions": list(role.permissions),
            "parent_role_id": str(role.parent_role_id) if role.parent_role_id else None,
        },
    )
    logger.info("Created role %s (id=%s)", role.name, role.id)
    return RoleRead.model_validate(role)

View on GitHub (pinned to 976ec789d2)

Solutions

  1. On 409, GET /api/v1/authz/roles and reuse the existing role instead of creating it
  2. Use upsert-style logic in scripts: check by name, create only if missing
  3. Pick a different, namespaced name (e.g. 'team-dev') for custom roles

Example fix

// before
await api.post('/authz/roles', { name: 'developer' });

// after
const roles = await api.get('/authz/roles');
let role = roles.find(r => r.name === 'developer');
if (!role) role = (await api.post('/authz/roles', { name: 'developer' })).data;
Defensive patterns

Strategy: try-catch

Validate before calling

const roles = await api.get('/api/v1/authz/roles');
if (roles.some(r => r.name === name)) return roles.find(r => r.name === name)!;

Try / catch

try { return await createRole(name, perms); }
catch (e) { if (e.status !== 409) throw e; return (await listRoles()).find(r => r.name === name)!; }

Prevention

When it happens

Trigger: POST {"name": "developer"} when a custom (or system) role named 'developer' already exists; system roles viewer/developer/admin are seeded by the authz foundations migration, so re-creating those names always conflicts.

Common situations: Re-running provisioning scripts that assume create-if-missing semantics, or attempting to recreate a system role as a custom role. The 409 detail includes the name via {payload.name!r} to make the conflict obvious.

Related errors


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