Odoo debug
Odoo debugging and troubleshooting for versions 17.0, 18.0, 19.0 (Community & Enterprise). Covers debug mode, logging, ORM query analysis, shell, common errors and fixes, performance profiling, and developer tools. Use when user asks about debugging Odoo, errors, performance, logs, shell, or invokes /odoo-debug.From its SKILL.md
npx -y skills add halim-23/odoo-dev-plugin --skill odoo-debugAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.8 KB, as published. Nobody here has run it
Expert Odoo debugger. Target: 17/18/19 CE+EE.
Enable Debug Mode
# URL parameter
https://myodoo.com/web?debug=1 # debug mode
https://myodoo.com/web?debug=assets # also disables asset bundling
https://myodoo.com/web?debug=0 # disable
# Settings → General Settings → Developer Tools → Activate the developer mode
Logging Configuration
# odoo.conf
log_level = debug # debug, info, warning, error, critical
log_handler = :DEBUG # all loggers at DEBUG
# Per-module logging in conf:
log_handler = odoo.addons.my_module:DEBUG,odoo.sql_db:DEBUG
# Or at runtime (restart not needed with RPC):
import logging
_logger = logging.getLogger(__name__)
_logger.debug("Debug: %s", variable)
_logger.info("Info: %s", value)
_logger.warning("Warning")
_logger.error("Error: %s", e, exc_info=True)
Odoo Shell
# Start shell for database mydb
python odoo-bin shell -d mydb --no-http
# Useful shell commands
env['my.model'].search([])
env['my.model'].browse(1).read()
env['my.model'].browse(1).name_get()
# Check field value
rec = env['my.model'].browse(5)
print(rec.name, rec.state, rec.partner_id.name)
# Execute method
rec.action_confirm()
env.cr.commit() # commit if you want to persist
# Rollback if testing
env.cr.rollback()
# Run as different user
env2 = env(user=env.ref('base.user_demo'))
env2['my.model'].search([])
SQL Query Logging
# In odoo.conf:
log_handler = odoo.sql_db:DEBUG
# Or per-session in code:
import logging
logging.getLogger('odoo.sql_db').setLevel(logging.DEBUG)
# Count queries in a block
from odoo.tools import sql
# Use profiler (v15+)
with env.cr.savepoint():
from odoo.tools.profiler import Profiler
with Profiler():
records = env['my.model'].search([])
Common Errors & Fixes
MissingError: Record does not exist
# Wrong: browsing deleted record
rec = env['my.model'].browse(99999)
rec.name # raises MissingError
# Fix: check exists
rec = env['my.model'].browse(99999)
if rec.exists():
print(rec.name)
psycopg2.IntegrityError: FOREIGN KEY violation
- Check
ondelete=on Many2one fields - Ensure
ir.model.access.csvallows unlink - Check
_sql_constraintsunique violations
UserError: You cannot delete a record
- Model has
unlink()override with check — read error message - Record in "done" or locked state
AttributeError: 'my.model' object has no attribute 'xyz'
- Field not defined in model
- Module not updated:
python odoo-bin -d mydb -u my_module
ValueError: External ID not found
- Missing
ref="..."in XML data - Module not installed — check
dependsin manifest
ir.rule hiding records unexpectedly
# Debug: check which rules apply
env['ir.rule'].sudo()._get_domain(env['my.model'], 'read')
# Or bypass rules temporarily with sudo
records = env['my.model'].sudo().search([])
Computed field not updating
# Force recompute
rec.modified(['dependency_field'])
rec._recompute_recordset()
# Or: mark for recompute
env.add_to_compute(rec._fields['computed_field'], rec)
Translation not found / strings not translating
# Regenerate .po file
python odoo-bin --i18n-export=/tmp/my_module.pot -d mydb -l en_US --modules=my_module
# Import translations
python odoo-bin --i18n-import=/tmp/my_module_fr.po -d mydb -l fr_FR --modules=my_module
Performance Debugging
N+1 Query Detection
# BAD: N+1
for rec in records:
print(rec.partner_id.name) # query per record
# GOOD: prefetch (Odoo does this automatically with browse, but explicit for clarity)
records.mapped('partner_id.name') # single query
Disable Prefetch (for memory)
env['my.model'].with_prefetch().search([]) # custom prefetch set
env['my.model'].with_context(prefetch_fields=False).search([])
Analyze Slow Queries
-- In psql
EXPLAIN ANALYZE
SELECT * FROM my_model WHERE state = 'draft' ORDER BY name;
-- Check missing indexes
SELECT schemaname, tablename, attname, n_distinct, correlation
FROM pg_stats
WHERE tablename = 'my_model';
Add index in Python:
partner_id = fields.Many2one('res.partner', index=True)
Profiling (v15+)
# Enable profiler from Settings → Technical → Profiler
# Or programmatically:
from odoo.tools.profiler import Profiler, profiler
with Profiler(db=env.cr.dbname):
slow_method()
Upgrade / Update Module
# Update specific module
python odoo-bin -d mydb -u my_module
# Update with dependencies
python odoo-bin -d mydb -u my_module,dep_module
# Run tests during update
python odoo-bin -d mydb -u my_module --test-enable --test-tags my_module
# Full upgrade (slow)
python odoo-bin -d mydb -u all
Browser Dev Tools (OWL)
// In browser console:
// Get OWL component from DOM element
const el = document.querySelector('.o_my_component');
const component = owl.__apps__[0].getNode(el)?.component;
// Access env services
odoo.__DEBUG__.services['orm']
odoo.__DEBUG__.services['notification']
Backend URL Navigation (Version-Critical)
Odoo changed its URL routing system between versions. Always use the correct format for the target version.
Odoo 17.0 — Hash-based routing
# Navigate by action ID or XML ID (resolved via /web/action/load)
http://host/web#action=<action_id>&cids=1
http://host/web#action=my_module.action_my_model&cids=1
# Navigate to menu (expands the menu and loads its action)
http://host/web#menu_id=<menu_id>&cids=1
# Combine action + menu (menu highlighted, action loaded)
http://host/web#action=<action_id>&menu_id=<menu_id>&cids=1
# Debug mode — append to hash or as query param before hash
http://host/web?debug=1#action=<action_id>&cids=1
Odoo 18.0 / 19.0 — Path-based routing
# Path segments derived from model _name (dots → dashes, strip odoo.* prefix)
http://host/odoo/payroll
http://host/odoo/employees
http://host/odoo/my-model/<id>
# Debug mode
http://host/odoo?debug=1
http://host/odoo/my-model?debug=assets
Do NOT use
/odoo/...paths in Odoo 17.0 — they are invalid and will 404. Do NOT useweb#action=...hash routing in Odoo 18/19 — the hash is ignored.
Finding IDs at runtime (v17)
# In odoo-bin shell or RPC — find action/menu IDs
env['ir.actions.act_window'].search_read([('res_model','=','my.model')], ['id','name'])
env['ir.ui.menu'].search_read([('name','ilike','My Menu')], ['id','complete_name'])
Version-Specific Debug
v17: Debug mode toggle in URL: ?debug=assets disables bundle minification.
v17: ?debug=tests runs browser QUnit tests.
v17: URL routing is hash-based (/web#action=...) — see "Backend URL Navigation" above.
v18: Built-in query profiler in Settings when debug mode active.
v18/v19: URL routing is path-based (/odoo/...) — hash routing no longer works.
v19: ODOO_DISABLE_ASSETS_CACHE=1 env var forces asset recompilation.
Useful One-liners (Shell)
# Find all records in error state
env['my.model'].search([('state', '=', 'error')]).mapped('name')
# Check user permissions
user = env.ref('base.user_demo')
user.has_group('my_module.group_my_module_manager')
# Inspect field definitions
env['my.model']._fields['state']
env['my.model']._fields['state'].selection
# Find XML ID of a record
env['ir.model.data'].search([('model', '=', 'res.partner'), ('res_id', '=', 1)])
# Recompute all stored fields of model
env['my.model']._recompute_all() # v17+
# Flush pending writes
env.flush_all()