Skip to main content

Chapter 4 of 7 · Who can do what

Roles, permissions and user permissions

Four checks on a document, a different path for a list.

Reviewed 14 Oct 20263 min readFrappe v16.52.0

Frappe answers "can this user do this to this document?" with four checks, in order. Each one can say no. For a list it asks a different set of questions. Most "permission not working" reports are one person testing one path while the system uses the other.

Set up a case below, and watch the checks for a document and for a list side by side.

Try it

Can this user do it?

Pick a case, or set the inputs. The two columns are the two ways Frappe asks: one document, and a list.

Try a case

The user and the right

Opening the document

Allowed
  1. AdministratorPassed

    permissions.py:108–110

    Not Administrator, so the checks run.

  2. has_permission hook

    permissions.py:483–500

    No hook set. A hook can only deny.

  3. Role permissionPassed

    permissions.py:243–261, 316–340

    A role of this user grants it.

  4. User PermissionsPassed

    permissions.py:353–480

    This user has no User Permission for Company.

  5. Sharing

    permissions.py:209–211

    Not needed.

Seeing it in the list

Shown
  1. Administrator

    permissions.py:108–110

    Not reached in this case.

  2. Read right on the DocTypePassed

    db_query.py:1052–1058

    A role grants read.

  3. Owner condition

    db_query.py:1069–1073

    Not reached in this case.

  4. User Permission conditions

    db_query.py:1114–1171

    None for this user.

  5. permission_query_conditions

    db_query.py:1173–1196

    No hook excludes it.

  6. has_permission hook

    db_query.py:630–639

    Not asked per row: lists use the SQL conditions above.

  7. Sharing

    db_query.py:1099–1101

    Not reached in this case.

Frappe v16.52.0, with v15.123.0 where marked. A case, not a measurement: it runs the order Frappe uses, not your site.

What are the four checks on one document?

The controller hook. A has_permission hook can deny. It cannot grant. On v16 a hook that returns None denies. On v15, None meant no opinion, and the official Hooks page still describes that older behaviour.

The role. The DocType's Permissions table has a row per role: read, write, create, submit, cancel, delete and the rest, at a permission level. For the document itself only level 0 counts. A row marked "If owner" gives the right only to the person who created the document.

User Permissions. These restrict a user to certain records, for example one Company. Frappe checks the document's own DocType first, then every Link field on it and on its child rows. A Link field flagged "Ignore User Permissions" is skipped. An empty link passes unless "Apply Strict User Permissions" is on in System Settings.

Sharing. If the first three said no, a share on that one document can still allow read, write, share, submit, email or print.

Administrator passes everything, so test as the user, never as Administrator.

Why does a list behave differently?

A list is one SQL query, so Frappe cannot ask a hook about each row. It builds conditions instead. The role must grant read. An "If owner" role adds owner = you. Each User Permission adds "this Link field is empty, or in the allowed values", and strict mode drops the "empty" part. permission_query_conditions hooks add their own SQL. Shared documents are added back.

The has_permission hook is not asked per row. So a document can show in the list and refuse to open, or open from a link and be missing from the list. get_all skips all of this.

What do permission levels do?

A field can sit at a permission level above 0, and a role is granted levels separately. A user without write at level 1 can open and save the document, but their changes to level-1 fields are quietly put back to the old values, with no error. A read removes the fields the user may not read. A child row uses its parent's permissions.

Why is my user permission not working?

Five causes, in the order to check them. The user has no User Permission for the linked DocType, so nothing filters. The Link field is flagged "Ignore User Permissions". The field is empty and strict mode is off. The role is "If owner" only. You tested as Administrator.

Where this comes from

Read at Frappe v16.52.0 and ERPNext v16.50.0. “(v15)” marks Frappe v15.123.0 and “(ERPNext v15)” marks ERPNext v15.122.0. Each link opens that file at that tag, on that line.

Your next step

See it live

Run a sprint

Finish a task in this week's sprint, log the hour it took, and see the sprint's burndown, all on ERPNext's own records.

You end with hours booked on a task · 2 screens · about 3 min

No sign-up, no card, no account.

Next step · Architecture guide

Now see how we build a Frappe app

A separate app in your own Git, so upgrades keep working.