Skip to content

Odoo Invalid Search Domain — 'Invalid domain' and Filter Errors Fix

DeployMonkey Team · March 24, 2026 9 min read

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.