跳至主要内容

res.users 上的 Odoo AccessError:如何在 2019 年 17 月 18 日修复它

遇到 AccessError:您不允许在 Odoo 中访问 res.users?诊断安全组或记录规则并立即在生产中永久修复它。

E
ECOSIRE Research and Development Team
|2026年5月4日7 分钟阅读1.3k 字数|

本文目前仅提供英文版本。翻译即将推出。

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:

  1. 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_1024 and the visitor is not logged in as an internal user.
  2. A controller method runs with request.env (which uses the calling user) instead of request.env.with_user(SUPERUSER_ID) for an explicitly public action.
  3. A computed field reads user_id.something without sudo() and is rendered in a list view that any portal user can see.
  4. A model inherits something that reads res.users in _compute_*. The compute runs in the requesting user's context.
  5. 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: every sudo() 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 of res.users without sudo() 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 AccessError regressions ship because nobody tested as a non-admin.
  • Use computed fields with compute_sudo=True for 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.

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.

分享:
E

作者

ECOSIRE Research and Development Team

技术写作

ECOSIRE 技术写作团队的内容涵盖 Odoo ERP、Shopify 电子商务、AI 智能体、Power BI 分析、GoHighLevel 自动化以及企业软件最佳实践。我们的指南帮助企业做出明智的技术决策。

ECOSIRE

使用 Odoo ERP 转变您的业务

专家 Odoo 实施、定制和支持可简化您的运营。