Invalid Domain Errors in Odoo
Search domains are the filter expressions used throughout Odoo. When they are malformed, you get:
ValueError: Invalid domain [('state' '=' 'draft')]
KeyError: Invalid field 'x_custom_field' in domain
TypeError: Invalid leaf ('partner_id.name', 'ilike')
Traceback: ... invalid domain term ['state', 'draft']
... not enough values to unpack (expected 3, got 2)Domain Syntax Rules
An Odoo domain is a list of tuples, each with exactly three elements:
# Correct domain syntax
[('field_name', 'operator', value)]
# Multiple conditions (implicit AND)
[('state', '=', 'draft'), ('partner_id', '!=', False)]
# OR conditions use '|' prefix operator
['|', ('state', '=', 'draft'), ('state', '=', 'sent')]
# AND is default but can be explicit
['&', ('state', '=', 'draft'), ('active', '=', True)]Fix 1: Missing Commas in Tuples
The most common syntax error:
# Wrong — missing comma between elements
[('state' '=' 'draft')]
# Right
[('state', '=', 'draft')]
# Wrong — missing comma between tuples
[('state', '=', 'draft')('active', '=', True)]
# Right
[('state', '=', 'draft'), ('active', '=', True)]Fix 2: Wrong Number of Elements
# Wrong — only 2 elements (missing operator or value)
[('state', 'draft')]
# Right — must have field, operator, value
[('state', '=', 'draft')]
# Wrong — 4 elements
[('state', '=', '!=', 'draft')]
# Right
[('state', '!=', 'draft')]Fix 3: Invalid Operators
# Valid operators:
# =, !=, >, >=, <, <=
# in, not in
# like, ilike, not like, not ilike
# =like, =ilike
# child_of, parent_of
# Wrong operators:
[('state', '==', 'draft')] # Use '=' not '=='
[('state', 'equals', 'draft')] # Not a valid operator
[('id', 'IN', [1,2,3])] # Case sensitive: use 'in' not 'IN'
# Right
[('state', '=', 'draft')]
[('id', 'in', [1, 2, 3])]Fix 4: Field Does Not Exist
# Error: Invalid field 'x_custom_field'
# The field was removed or the module adding it is not installed
# Check if field exists
sudo -u postgres psql -d mydb -c "
SELECT name, model FROM ir_model_fields
WHERE name = 'x_custom_field';
"
# Check saved filters/actions referencing this field
sudo -u postgres psql -d mydb -c "
SELECT id, name, domain FROM ir_filters
WHERE domain LIKE '%x_custom_field%';
SELECT id, name, domain FROM ir_act_window
WHERE domain LIKE '%x_custom_field%';
"
# Fix: remove or update the filter/action
sudo -u postgres psql -d mydb -c "
DELETE FROM ir_filters WHERE domain LIKE '%x_custom_field%';
"Fix 5: Prefix Operator Errors
# Wrong — OR with wrong number of following conditions
['|', ('state', '=', 'draft'), ('state', '=', 'sent'), ('state', '=', 'done')]
# '|' only takes the NEXT 2 conditions
# Right — nested OR for 3+ conditions
['|', '|', ('state', '=', 'draft'), ('state', '=', 'sent'), ('state', '=', 'done')]
# Or use 'in' operator
[('state', 'in', ['draft', 'sent', 'done'])]Fix 6: Domains in XML Views and Actions
[('state', '=', 'draft')]
[('state', '=', 'draft')]
[('state', '=', 'draft')]
[('state', '=', 'draft')]Fix 7: Domain Evaluation in Odoo Shell
# Test your domain in odoo shell
odoo shell -d mydb
# Test domain validity
domain = [('state', '=', 'draft'), ('partner_id', '!=', False)]
results = env['sale.order'].search(domain)
print(f"Found {len(results)} records")
# Debug complex domains
from odoo.osv import expression
normalized = expression.normalize_domain(domain)
print(normalized)Prevention
DeployMonkey's AI agent validates search domains in custom modules before deployment. Malformed domains are detected during code review, preventing runtime filter errors in production.