Este artigo está atualmente disponível apenas em inglês. Tradução em breve.
A user clicks a button, opens a record, or runs a custom report and Odoo throws this on the screen:
A user clicks a button, opens a record, or runs a custom report and Odoo throws this on the screen:
odoo.exceptions.AccessError: You are not allowed to access "Users" (res.users) records.
- Operation: read
- User: 12 (Mark T)
- Required model access groups for "res.users":
- base.group_erp_manager
This shows up in Odoo 17.0, 18.0, and 19.0. It is almost never the user's fault — your code (or a third-party module) is reading res.users from a context where the current user does not have permission. The fix is rarely "give the user admin"; that is the wrong answer 95 percent of the time.
Quick Fix
In your custom code, replace direct reads of res.users with a sudo() read on the specific field you need, then drop the elevated context:
# WRONG — fails for non-admins
manager_email = order.user_id.email
# RIGHT — read one field with sudo, no privilege escalation beyond that
manager_email = order.sudo().user_id.email
# or, if you need the user record itself:
manager = order.user_id.sudo()
If the error happens in a third-party module you cannot edit, add the user to the base.group_user group (Internal User) — res.users is readable by any internal user by default. The error usually means the affected user is a Portal or Public user.
Why This Happens
res.users has a strict ACL. Reads require base.group_user (Internal User) or higher. Writes require base.group_erp_manager (Administration: Settings). Record rules further restrict which users a given user can see. The error fires when:
- A portal/public user triggers a flow that reads a user field. Typical example: a website controller renders a sale order with
order.user_id.partner_id.image_1024and the visitor is not logged in as an internal user. - A controller method runs with
request.env(which uses the calling user) instead ofrequest.env.with_user(SUPERUSER_ID)for an explicitly public action. - A computed field reads
user_id.somethingwithoutsudo()and is rendered in a list view that any portal user can see. - A model inherits something that reads
res.usersin_compute_*. The compute runs in the requesting user's context. - A cron or automated action runs as a user that does not have
base.group_user. (Crons should run as admin or as a dedicated bot user.)
Step-by-Step Diagnosis
1. Identify the user and the model. The traceback always names the user id and the model. Note both.
2. Check the user's groups. Open Settings > Users & Companies > Users, select the user, and look at the "Access Rights" tab. Does the user have User types > Internal User? If they are Portal or Public, that is your problem.
3. Reproduce in a shell. Open odoo-bin shell -c odoo.conf -d <db>:
user = env['res.users'].browse(12)
env['res.users'].with_user(user).check_access_rights('read', raise_exception=False)
# False means access is forbidden
If check_access_rights returns False, ACL is the issue. If it returns True, the problem is a record rule.
4. Inspect record rules.
rules = env['ir.rule'].sudo().search([('model_id.model', '=', 'res.users')])
for rule in rules:
print(rule.name, rule.domain_force, rule.groups.mapped('name'))
Look for rules that exclude the affected user. Multi-company rules are a frequent culprit — the user might not have the relevant company in company_ids.
5. Find the offending read in your code. Use git grep for \.user_id\. and any env['res.users']. Each one is a candidate. The traceback's last user-code frame is usually the answer.
Permanent Fix
The right fix depends on intent.
If the read is intentional public data (the sales rep's name on a public quotation page), use sudo() on the smallest scope:
class SaleOrder(models.Model):
_inherit = 'sale.order'
salesperson_name = fields.Char(compute='_compute_salesperson_name')
def _compute_salesperson_name(self):
for order in self:
order.salesperson_name = order.sudo().user_id.name or ''
If the read is admin-only, add an explicit guard so the error message is meaningful:
def action_reassign(self):
if not self.env.user.has_group('sales_team.group_sale_manager'):
raise UserError(_("Only Sales Managers can reassign orders."))
...
If a website controller is the source, decorate the route or add auth='public' only when you genuinely intend public access, and guard your env reads:
@http.route('/my/orders', auth='user', website=True)
def my_orders(self, **kw):
orders = request.env['sale.order'].search([('partner_id', '=', request.env.user.partner_id.id)])
# safe — user is logged in and reading their own orders
If a cron is failing, set the cron's user to a dedicated bot account with the right groups, or admin if the action genuinely requires it.
How to Prevent It
- Make
sudo()audit-grep-able. Establish a team rule: everysudo()call gets a one-line comment explaining why. This makes security reviews cheap and surfaces accidental privilege escalation immediately. - Lint for
request.env['res.users']. Any controller-side read ofres.userswithoutsudo()is suspect. Catch it pre-merge. - Test as portal user. Add a Playwright or Hoot test that signs in as a portal account and exercises every public route. Most
AccessErrorregressions ship because nobody tested as a non-admin. - Use computed fields with
compute_sudo=Truefor fields that aggregate user data:
salesperson_name = fields.Char(compute='_compute_salesperson_name', compute_sudo=True)
compute_sudo=True runs the compute in superuser context, sidestepping ACL while keeping the read explicit and auditable.
- Multi-company sanity check. New users must be added to all companies they need access to (
company_ids), not just one (company_id). The Odoo UI hides this distinction.
Related Errors
- MissingError: Record does not exist — record rules can surface as MissingError instead of AccessError.
- ValidationError: Required field not set — different error class, same wave of post-deploy fallout.
- Expected singleton — common companion error in the same code path.
Frequently Asked Questions
Why does sudo() fix this — am I bypassing security?
sudo() runs that one ORM call as superuser. It bypasses ACL and record rules for that call only. It is not a global escalation. Use it for reads where the user genuinely needs the value (a salesperson's name on a public page), and never for writes that the user should not be allowed to make.
Should I add the user to base.group_erp_manager?
Almost never. That group grants Administration: Settings, which is a superpower. The right answer is base.group_user (Internal User) for staff, base.group_portal for customers, and sudo() in code for the specific reads that cross those boundaries.
How do I see exactly which record rule is blocking the user?
Enable Developer Mode, open Technical > Security > Record Rules, filter by model res.users. Each rule shows its domain and the groups it applies to. To debug live, run env['ir.rule']._compute_domain('res.users', 'read') in a shell as the affected user — that returns the combined domain Odoo applies.
My cron worked yesterday and started failing today. What changed?
Check ir.cron.user_id on the failing cron. A migration or restore can reset the cron's user to a default that lacks the right groups. Set it back to admin (or a dedicated bot) and the error goes away. ECOSIRE's Odoo migration team hits this on every major version upgrade.
How do I audit every sudo() in my codebase?
grep -rn "\.sudo()" /opt/odoo/custom/ | wc -l
Anything over a few dozen warrants review. Pair the count with grep -B1 ".sudo()" to read the line above each — if it does not have a # why-sudo: comment, add one or refactor.
What is the difference between sudo() and with_user(SUPERUSER_ID)?
sudo() is a shortcut for with_user(SUPERUSER_ID) plus an internal flag that propagates through related-record reads. with_user(uid) switches to a specific user. Use sudo() for "I need superuser for this read", with_user(uid) for "I need to act as a specific other user" (rare, mostly tests).
Need help with a tricky Odoo error? ECOSIRE's Odoo experts have shipped 215+ modules — get expert help.
Escrito por
ECOSIRE Research and Development TeamRedação técnica
A equipe de redação técnica da ECOSIRE escreve sobre Odoo ERP, e-commerce com Shopify, agentes de IA, análise de dados com Power BI, automação com GoHighLevel e boas práticas de software empresarial. Nossos guias ajudam as empresas a tomar decisões de tecnologia bem fundamentadas.
ECOSIRE
Transforme seu negócio com o Odoo ERP
Implementação, personalização e suporte especializado do Odoo para agilizar suas operações.
Artigos Relacionados
Segmentação de clientes baseada em IA: do RFM ao clustering preditivo
Saiba como a IA transforma a segmentação de clientes, desde a análise estática de RFM até o clustering preditivo dinâmico. Guia de implementação com dados Python, Odoo e ROI real.
IA para otimização da cadeia de suprimentos: visibilidade, previsão e automação
Transforme as operações da cadeia de suprimentos com IA: detecção de demanda, pontuação de risco de fornecedores, otimização de rotas, automação de armazéns e previsão de interrupções. Guia 2026.
Guia de ecommerce B2B de atacado: portais, prazos de pagamento e preços por cliente
Monte um portal de atacado B2B que os compradores realmente usam: preços por cliente, prazos e limites de crédito, checkout com pedido de compra e aprovações, e recompras pelo histórico.