Module
queue_job
Describe the bug
https://github.com/OCA/queue/blob/19.0/queue_job/controllers/main.py#L218
env = http.request.env(user=SUPERUSER_ID)
I believe needs to be
http.request.update_env(user=SUPERUSER_ID)
env = http.request.env
runjob is declared as auth=none.
https://github.com/OCA/queue/blob/19.0/queue_job/controllers/main.py#L212
_auth_method_none forces uid=None for request env and default_env
https://github.com/odoo/odoo/blob/19.0/odoo/addons/base/models/ir_http.py#L263
So env = http.request.env(user=SUPERUSER_ID)
only produces a local env with that superuser, the other two are still None.
The job "itself" runs fine as the specified user, but any flush/recompute on a stored field uses the default_env with uid None.
We see a singleton error on is_backend_user = self.env.user.has_group('base.group_user') (in Odoo Enterprise compute_signing_user) because self.env.user is an empty recordset.
File ".../odoo/orm/environments.py", line 592, in flush
self.default_env.flush_all()
...
File ".../enterprise/account_accountant/models/account_move.py", line 76, in _compute_signing_user
is_backend_user = self.env.user.has_group('base.group_user')
File ".../odoo/addons/base/models/res_users.py", line 1074, in has_group
self.ensure_one()
ValueError: Expected singleton: res.users()
The default_env mechanism was introduced 2 years ago
odoo/odoo@897e2f2
but the flush() was tolerant. Ironically,
odoo/odoo@45e1c05
(Jan 24 2025) states "flush as public user when there is no default_env"
but now _auth_method_none always sets default_env
odoo/odoo@45e1c05#diff-c5500b83255cdef56ed07cb5a74e9b0899ad378cf9a3739d9676101191c83eb2
Using update_env repoints the default_env correctly
https://github.com/odoo/odoo/blob/19.0/odoo/http.py#L1836
To Reproduce
Affected versions: 19.0
Steps to reproduce the behavior:
- Create a module with a computed attribute that accesses
self.env.user (I added an explicit flush to force the pending compute):
class ResPartner(models.Model):
_inherit = "res.partner"
x_toucher = fields.Many2one("res.users", store=True, compute="_c")
@api.depends("name")
def _c(self):
self.env.user.has_group("base.group_user") # ensure_one() fails on empty recordset
for r in self:
r.x_toucher = self.env.user
def touch(self):
self.write({"name": "x"})
self.env.cr.flush() # forces Transaction.flush() -> default_env.flush_all()
- Enqueue a write that causes a flush:
partner.with_delay().touch()
- Run the jobrunner -> job fails with Expected singleton: res.users().
Expected behavior
self.env.user inside stored-field recomputes triggered during a queue job should resolve to a real user (the job's user_id or SUPERUSER), not an empty recordset.
Additional context
In the same commit (45e1c05), core updated the two other places that create a uid=None env to set default_env explicitly:
- odoo/service/common.py::exp_authenticate assigns
env.transaction.default_env = env directly.
- addons/bus/websocket.py added a
new_env() helper that does the same.
Neither can use Request.update_env because they don't run inside an HTTP Request.
queue_job/controllers/main.py::runjob does run inside a Request, so the idiomatic fix is http.request.update_env(user=SUPERUSER_ID), which has been repointing default_env since 897e2f2.
Module
queue_job
Describe the bug
https://github.com/OCA/queue/blob/19.0/queue_job/controllers/main.py#L218
I believe needs to be
runjobis declared asauth=none.https://github.com/OCA/queue/blob/19.0/queue_job/controllers/main.py#L212
_auth_method_noneforcesuid=Nonefor request env and default_envhttps://github.com/odoo/odoo/blob/19.0/odoo/addons/base/models/ir_http.py#L263
So
env = http.request.env(user=SUPERUSER_ID)only produces a local env with that superuser, the other two are still None.
The job "itself" runs fine as the specified user, but any flush/recompute on a stored field uses the default_env with uid
None.We see a singleton error on
is_backend_user = self.env.user.has_group('base.group_user')(in Odoo Enterprisecompute_signing_user) becauseself.env.useris an empty recordset.The default_env mechanism was introduced 2 years ago
odoo/odoo@897e2f2
but the flush() was tolerant. Ironically,
odoo/odoo@45e1c05
(Jan 24 2025) states "flush as public user when there is no default_env"
but now
_auth_method_nonealways setsdefault_envodoo/odoo@45e1c05#diff-c5500b83255cdef56ed07cb5a74e9b0899ad378cf9a3739d9676101191c83eb2
Using
update_envrepoints the default_env correctlyhttps://github.com/odoo/odoo/blob/19.0/odoo/http.py#L1836
To Reproduce
Affected versions: 19.0
Steps to reproduce the behavior:
self.env.user(I added an explicit flush to force the pending compute):partner.with_delay().touch()Expected behavior
self.env.userinside stored-field recomputes triggered during a queue job should resolve to a real user (the job's user_id or SUPERUSER), not an empty recordset.Additional context
In the same commit (45e1c05), core updated the two other places that create a uid=None env to set default_env explicitly:
env.transaction.default_env = envdirectly.new_env()helper that does the same.Neither can use
Request.update_envbecause they don't run inside an HTTP Request.queue_job/controllers/main.py::runjob does run inside a Request, so the idiomatic fix is
http.request.update_env(user=SUPERUSER_ID), which has been repointing default_env since 897e2f2.