Sunday, August 30, 2026
1 change · saas-19.3
Resolved issues and error corrections
This fix prevents quotation emails from failing for customers with large attachment databases. Odoo now limits attachment access checks to the documents relevant to the sale, avoiding broad searches that could hit system limits and block quote sending.
Original PR description
## Context Recently, we've had larger customers upgrading to 19.3. These customers began noticing that they were unable to send any quotations from their sale orders. It turned out that they were all…
## Context
Recently, we've had larger customers upgrading to 19.3. These customers began noticing that they were unable to send any quotations from their sale orders. It turned out that they were all experiencing the same issue that could be traced back to some of our ORM optimization code.
The problem had to do with an unbounded search on the `ir.attachment` model. This would happen when trying to load the relevant product documents to attach in a confirmation email, based on the products being sold. Where we should have been checking the user's "read" access on only the attachments being added to the email, we were checking "read" access for every single attachment in the database. This was hitting our search limit and preventing them from sending out quotes.
At the time of writing, `MAX_SEARCH_LIMIT` evaluates to `10,000`.
https://github.com/odoo/odoo/blob/f5ace41946dce669f72d1edeef3daebfdb4a4519/odoo/addons/base/models/ir_attachment.py#L660-L663
## Before this commit
When a search on a model reaches a related field through the `any` operator, and the model's own `search_domain` doesn't mention that field directly, the optimizer fell back to accepting all comodel records (`Domain.TRUE`). The comodel's own search then had no restriction to work with and scanned every row:
https://github.com/odoo/odoo/blob/f5ace41946dce669f72d1edeef3daebfdb4a4519/odoo/orm/domains.py#L1465-L1467
On `ir.attachment`, we'd hit that limit for larger customers easily, and then raise,
ValueError: Cannot search, too many attachments
## After this commit
Instead of discarding the outer `search_domain`, we build a lazy subquery of the records it actually reaches and pass that to the comodel as `context['search_domain']`. The comodel-side search can opt in to use it to narrow itself down; if it doesn't, nothing changes. The subquery is only ever executed if something reads it, so there's no cost when it isn't used. For `ir.attachment`, this restores the scoping and the search stays bounded.
The `domains.py` fix assumes that `context['search_domain']` describes the current model. But a few `_search_res_access`-style methods switch to a different comodel via `env[res_model_name]` without clearing that
key, so it leaks over from the original model. That was harmless with the old `Domain.TRUE` fallback, but the new lazy subquery actually builds SQL from it, so it crashes when the leaked domain references a field the comodel doesn't have.
Also, it is necessary that we include `bypass_access=True` on our subquery's `_search()` to avoid infinite recursion through our security domain optimization code. It's safe here because we're building it as a helper query based on records already deemed accessible to the user. So, both the outer model's and the comodel's security domains are
still going to be applied on their respective final queries.
## TODO in master
The real fix for the leak is to have `context['search_domain']` carry the model it was computed for, instead of a bare `Domain`, so a mismatch can be detected rather than acted on. That touches `models.py`'s `_search`, `ir_rule.py`'s domain computation, and every `_search_res_access`-style method in `base`/`mail` that switches to a different comodel via `env[res_model_name]` without clearing the key. That's a bigger change than we want in this fix, so I've left it for a follow-up on master.
opw-6486492