The ticket: a sales rep cannot open a modified order form
The setup is ordinary. A team customised the sales order form view — a few fields rearranged, a new tab for internal notes — and it worked for everyone during testing. On Monday, a sales rep reports they cannot open any sales order: clicking an order shows an access error instead of the form. Admins can open the same orders without trouble. The rep’s manager suspects “the new view broke it,” and the pressure is to roll the view back immediately.
Rollback is a reasonable instinct but a bad first move: if the problem is permissions, rolling back the view changes nothing and wastes the investigation. The playbook starts by establishing which family the error belongs to.
First: reproduce it properly
Before touching code, reproduce the failure under controlled conditions:
- Confirm the account. Log in (or impersonate, where the platform supports it) as the affected rep — not an admin, not a colleague “with the same role.” Access problems are frequently user-specific, and admins cannot reproduce them because admins bypass the rules that cause them.
- Record the exact action. Which menu, which record, which click — down to the record ID. “Cannot open orders” is a symptom; “error when opening SO-1042 from the Sales Orders list” is a reproduction.
- Note the error text precisely. Odoo distinguishes “You are not allowed to access X” from view-rendering errors and from missing-record errors. The wording tells you which family you are in — screenshot it, do not paraphrase it.
- Check whether it is all records or one. If the rep cannot open any order, suspect view or model-level access. If only some orders fail, suspect record rules or multi-company filters on those records.
Reading a redacted traceback: what to look for
When the view family is the suspect, the server log usually holds a traceback. The snippet below is an illustrative, redacted example of the shape — names, paths, and IDs replaced — showing what a view-inheritance failure looks like versus what an access failure looks like:llustrative redacted traceback — view-inheritance failure shape
Traceback (most recent call last):
File "[...]/odoo/models.py", line [...], in load_views
view = self.env['ir.ui.view']._get_view(view_id, view_type)
File "[...]/addons/web/controllers/main.py", line [...], in call_kw
return self._call_kw(model, method, args, kwargs)
ElementNotFoundError: Invalid view inheritance:
- parent view [...] not found for inheriting view [...]
- referenced field "x_custom_priority" does not exist on model "sale.order"
Hint shape: view layer. The XML or the field reference is wrong.
# Illustrative redacted traceback — access-rule failure shape
Traceback (most recent call last):
File "[...]/odoo/models.py", line [...], in check_access_rule
raise AccessError("You are not allowed to access [...]")
odoo.exceptions.AccessError: The requested operation cannot be completed
due to security restrictions.
Hint shape: permission layer. The view is fine; the user may not read
(or write) these records.
Two practical habits make tracebacks useful. First, read the last lines first — the exception type and message name the layer; the frames above it are just the path the request took. Second, compare the rep’s failing request against an admin’s succeeding request in the same log window: identical up to the access check, diverging exactly there, is the signature of a permissions problem.
The diagnostic matrix: checks in order
| Check | How | If positive, the fix is… |
|---|---|---|
| View inheritance validity | Open the customised view in the technical views list; check for inherited-view errors on save | Correct the XML — fix the parent reference or the field name |
| Referenced fields exist | Search the model for each custom field the view touches | Create the field or remove the reference |
| Model-level access (ACL) | Check the rep’s groups against the model’s access rights — read/write/create/unlink | Adjust the ACL entry for the group, or the user’s group membership |
| Record rules | Temporarily test with the rule deactivated in a staging copy — does the error clear? | Narrow the rule’s domain, or add an exception group for the role |
| Multi-company scoping | Check the failing record’s company against the rep’s allowed companies | Correct the record’s company or the user’s company access |
| Field-level access | Verify no group-restricted fields on the form are load-bearing for the rep | Move the field off the required path or widen the group |
Work the matrix top to bottom. The ordering is deliberate: view problems are cheaper to rule out and fix, and eliminating them first keeps you from “fixing” permissions that were never broken. A common trap is the record rule that predates the view change — the view did not cause it, it merely surfaced it by making the rep open a record they never opened before.
Fix validation: proving the fix actually fixed it
A fix is not done when the error disappears for the admin. Validate it the way the failure happened:
- Re-run the exact reproduction — the rep’s account, the same record, the same click — and confirm the form opens and the intended action (edit, confirm, print) works.
- Check the neighbouring cases: another rep in the same group, an order from a different company, a record the rep should still not see. A permissions fix that accidentally widens access is a new incident.
- Record what changed and why, in the ticket: which layer, which rule or view, and what the validation covered. The next identical ticket will arrive in weeks, and its debugger will be someone else.
One boundary to hold: never claim an AI tool or an automated check “verified” the fix. Automated scans can confirm the error text is gone; they cannot confirm the access model is correct. That confirmation is a human reading the rules.
Frequently asked questions
Should we roll back the view change first and investigate later?
Only if the business impact demands it and the rollback is safe. Rolling back a view will not fix a permissions problem, and it destroys the evidence of what the view actually did. Reproduce first, then decide.
Why did this work in testing and break for the rep?
Almost always because testing used an admin or a developer account. Access rules are user-shaped; a test that never logs in as the affected user has not tested access at all.
How do we tell a record-rule problem from an ACL problem?ACLs are model-wide (“may this user read sale orders at all”); record rules are row-specific (“may this user read these orders”). If the rep can open some orders but not others, think record rules. If they can open none, think ACLs — or views.
Can a custom view itself create an access error?
Indirectly, yes: a view that displays a related record (a linked contact, a pricelist) the user cannot read will fail on that relation. The error looks like a view problem and is fixed by correcting the relation’s visibility or the user’s access to it.
Next step
When the traceback points at the permission layer but the rule set is too tangled to read by hand, a project-aware diagnosis beats guessing. Use Ask Odoo for a project-aware diagnosis — describe the rep, the record, and the exact error, and get a structured read of which layer to fix before you change anything.



