odoo/odoo · error · UserError
Cannot get aggregation details from a line not using 'aggreg
Error message
Cannot get aggregation details from a line not using 'aggregation' engine
What it means
Raised by `_get_aggregation_terms_details()` on `account.report.expression`: this helper parses aggregation formulas by splitting them into `line_code.total` terms, so every expression in `self` must have `engine == 'aggregation'`. Passing any expression with a different engine (`domain`, `tax_tags`, `account_codes`, `external`) is a programming error.
Source
Thrown at addons/account/models/account_report.py:870
if domains:
sub_expressions |= self.env['account.report.expression'].search(Domain.OR(domains))
to_expand = sub_expressions.filtered(lambda x: x.engine == 'aggregation' and x not in result)
result |= sub_expressions
return result
def _get_aggregation_terms_details(self):
""" Computes the details of each aggregation expression in self, and returns them in the form of a single dict aggregating all the results.
Example of aggregation details:
formula 'A.balance + B.balance + A.other'
will return: {'A': {'balance', 'other'}, 'B': {'balance'}}
"""
totals_by_code = defaultdict(set)
for expression in self:
if expression.engine != 'aggregation':
raise UserError(_("Cannot get aggregation details from a line not using 'aggregation' engine"))
expression_terms = re.split('[-+/*]', re.sub(r'[\s()]', '', expression.formula))
for term in expression_terms:
if term and not re.match(r'^([0-9]*[.])?[0-9]*$', term): # term might be empty if the formula contains a negative term
line_code, total_name = term.split('.')
totals_by_code[line_code].add(total_name)
if expression.subformula:
if_other_expr_match = re.match(r'if_other_expr_(above|below)\((?P<line_code>.+)[.](?P<expr_label>.+),.+\)', expression.subformula)
if if_other_expr_match:
totals_by_code[if_other_expr_match['line_code']].add(if_other_expr_match['expr_label'])
return totals_by_code
def _get_matching_tags(self):
""" Returns all the signed account.account.tags records whose name matches any of the formulas of the tax_tags expressions contained in self.
"""
tag_expressions = self.filtered(lambda x: x.engine == 'tax_tags')View on GitHub (pinned to 1e661df964)
Solutions
- Filter first: `expressions.filtered(lambda e: e.engine == 'aggregation')._get_aggregation_terms_details()`
- If a term is genuinely computed another way, move it to an `aggregation`-engine expression or stop feeding it to this helper
Example fix
# before details = line.expression_ids._get_aggregation_terms_details() # may contain non-aggregation expressions # after details = line.expression_ids.filtered(lambda e: e.engine == 'aggregation')._get_aggregation_terms_details()
Defensive patterns
Strategy: type-guard
Validate before calling
agg_exprs = expressions.filtered(lambda e: e.engine == 'aggregation') details = agg_exprs._get_aggregation_terms_details()
Type guard
def is_aggregation_expression(expr) -> bool:
"""_get_aggregation_terms_details only accepts aggregation-engine expressions."""
return expr.engine == 'aggregation' Try / catch
from odoo.exceptions import UserError
try:
details = exprs._get_aggregation_terms_details()
except UserError:
details = exprs.filtered(lambda e: e.engine == 'aggregation')._get_aggregation_terms_details() Prevention
- Always filter recordsets by engine before calling engine-specific helpers
- Keep `_get_aggregation_terms_details` calls inside aggregation-related code paths only
When it happens
Trigger: Calling `expression._get_aggregation_terms_details()` where `expression` (or any record in the recordset) has an engine other than `'aggregation'`. In framework code this is called on `to_expand` candidates; in custom code it is usually called on an unfiltered expression recordset.
Common situations: Custom report tooling iterating over all expressions of a line/report without filtering by engine; changing an expression's engine after formulas were set; subclass code reusing the helper for validation.
Related errors
- Groupby feature isn't supported by '%(engine)s' engine. Plea
- In report '%(report_name)s', on line '%(line_name)s', with l
- Only a report without a root report of its own can be select
- Line "%(line)s" defines line "%(parent_line)s" as its parent
- The sections defined on a report cannot have sections themse
AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15).
Data as JSON: /api/errors/d5b94ae0a7ebd615.
Report an issue: GitHub.