Only one rule allowed with the same Role, level and if owner Error

Does anyone know what causes this error?

I am not entirely sure how this happens – likely due to conflicting Role Permission rules – but I ran into the same issue.

Interestingly, on my manual (non-dockerized) ERPNext test instance, everything worked fine.
However, on my dockerized production instance, I hit the exact same error – specifically for the Doctype Supplier and the role Purchase User.

Thanks to ChatGPT (my savior), I was able to trace the issue back to the database:
We had a duplicate entry in the DocPerm table for the same role, level, and owner condition – which ERPNext doesn’t allow.

Go into your docker container:

docker exec -it frappe_docker-backend-1 bash

Then open the bench console:

bench --site your-site-name console

Use the following code to inspect the permission rules (:warning: adjust filters as needed!):

# Custom Permissions for Purchase User on Supplier (Level 0)
custom_rules = frappe.get_all(
    "Custom DocPerm",
    filters={"parent": "Supplier", "role": "Purchase User", "permlevel": 0},
    fields=["name", "parent", "role", "permlevel", "if_owner", "read", "write", "create", "delete"]
)

# Standard Permissions for Purchase User on Supplier (Level 0)
standard_rules = frappe.get_all(
    "DocPerm",
    filters={"parent": "Supplier", "role": "Purchase User", "permlevel": 0},
    fields=["name", "parent", "role", "permlevel", "if_owner", "read", "write", "create", "delete"]
)

print("\nCustom DocPerms:")
for r in custom_rules:
    print(r)

print("\nDocPerms:")
for r in standard_rules:
    print(r)


This is what I got:

I had two identical DocPerm entries, which caused the conflict.

I removed one of them like this:

frappe.delete_doc("DocPerm", "sd4h8in4ph") # change the name accordingly here
frappe.db.commit()

That fixed the issue — at least for now.
I’ll monitor whether it reappears after migrations or image rebuilds.

Hope this helps someone else out there!

I migrated and also pulled a new image to my production instance. Still seems to work.