Debugging Odoo efficiently requires knowing which tool to reach for at each layer: Python exceptions, slow database queries, frontend JavaScript errors, and misconfigured records all need different approaches. This guide covers the full stack.
Layer 1 — Log Levels and Log Configuration
Odoo writes logs to stdout (or a file if configured). The log level controls verbosity:
# In odoo.conf
log_level = debug # debug | info | warn | error | critical
log_db = True # also write logs to ir.logging table in the DB
log_db_level = warning # minimum level to write to DB
For targeted logging without flooding output, use --log-handler:
# Only debug logs for your module, info for everything else
odoo-bin -c odoo.conf --log-handler=my_module:DEBUG --log-level=info
# Debug SQL queries
odoo-bin -c odoo.conf --log-handler=odoo.sql_db:DEBUG
Inside your Python code, use the standard Python logging module:
import logging
_logger = logging.getLogger(__name__)
class MyModel(models.Model):
_name = 'my.model'
def my_method(self):
_logger.debug('Entering my_method with ids: %s', self.ids)
_logger.info('Processing %d records', len(self))
_logger.warning('Unexpected state: %s', self.state)
_logger.error('Failed to process record %d', self.id)
Layer 2 — pdb and ipdb Breakpoints
Python's built-in debugger (pdb) and the enhanced ipdb let you pause execution and inspect state:
# Install ipdb in your virtual environment
pip install ipdb
# In your model code
def problematic_method(self):
import ipdb; ipdb.set_trace() # execution pauses here
result = self._compute_something()
return result
When execution hits the breakpoint, you get an interactive prompt in the terminal running Odoo:
(ipdb) self # print the recordset
(ipdb) self.name # inspect a field
(ipdb) n # next line
(ipdb) s # step into a function call
(ipdb) c # continue execution
(ipdb) p self.env.user.name # print expression
(ipdb) l # list surrounding source code
Important: Only use breakpoints with --workers=0 (single-process mode). Multi-worker mode causes the breakpoint to block a worker silently.
odoo-bin -c odoo.conf --workers=0
Layer 3 — Odoo Shell
The Odoo shell is an interactive Python REPL with a fully initialized Odoo environment — perfect for exploring data, testing ORM queries, and running one-off fixes without writing a module:
odoo-bin shell -d your_database_name
Inside the shell:
# env is pre-loaded
partners = env['res.partner'].search([('is_company', '=', True)], limit=5)
for p in partners:
print(p.name, p.email)
# Test a model method
order = env['sale.order'].browse(42)
order.action_confirm()
env.cr.commit() # persist changes (or rollback with env.cr.rollback())
# Inspect a computed field
print(order._fields['amount_total'].compute)
# Check which rules apply to a record
env['ir.rule']._get_failing(order, 'read')
Changes in the shell are in a transaction — call env.cr.commit() to save or env.cr.rollback() to discard.
Layer 4 — Developer Mode in the Browser
Activate developer mode via Settings → Activate Developer Mode or by appending ?debug=1 to any URL. Developer mode unlocks:
- Technical menu: Inspect and edit views, models, fields, actions, and access rules directly in the UI.
- View metadata: Hover over any field to see its technical name.
- RPC logging: Use
?debug=assetsto also rebuild and serve unminified JavaScript. - Edit views in place: Click the bug icon on any view to see the combined view XML.
Layer 5 — Browser DevTools for Frontend Debugging
Odoo's frontend is a JavaScript SPA. Use browser DevTools (F12) to debug it:
- Console tab: JavaScript errors and warnings. Look for
Uncaught Erroror RPC failures. - Network tab: Filter by
/web/dataset/call_kwto see all ORM RPC calls. Inspect request payload (model, method, args) and response for errors. - Sources tab: With
?debug=assets, set breakpoints in unminified Odoo JS. UseCtrl+Pto search for a file by name. - Application tab: Check localStorage for cached session data and cookies.
A common pattern: an RPC call fails silently in the UI. Open Network, click the failing call_kw request, and the response JSON will contain the Python traceback under error.data.debug.
Layer 6 — Database Query Debugging with pg_stat_activity
When Odoo is slow or locks up, the issue is often at the database layer:
-- Connect to PostgreSQL
psql -d your_database
-- See currently running queries
SELECT pid, now() - pg_stat_activity.query_start AS duration,
query, state
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC;
-- Find blocking queries
SELECT blocked.pid, blocked.query, blocking.pid AS blocking_pid,
blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE cardinality(pg_blocking_pids(blocked.pid)) > 0;
-- Kill a stuck query (replace 1234 with actual pid)
SELECT pg_terminate_backend(1234);
For slow query analysis, enable log_min_duration_statement in postgresql.conf:
log_min_duration_statement = 1000 # log queries taking more than 1 second
Then use EXPLAIN ANALYZE on the slow query to identify missing indexes.
Debugging on DeployMonkey Instances
DeployMonkey makes production debugging safer:
- Live log streaming: View real-time Odoo logs from the dashboard without SSH access.
- Shell access: Pro and Business plans include a browser-based Odoo shell for live data inspection.
- Log level control: Adjust log levels per-module from the Instance Settings panel without editing config files.
- Database snapshots: Take a manual backup before running risky debug-driven data fixes.
Combine with the ORM cheat sheet for efficient shell-based debugging.
FAQ
Why does my pdb breakpoint hang without showing a prompt?
Odoo is running in multi-worker mode. The breakpoint fires in a worker process that is not attached to your terminal. Restart Odoo with --workers=0 to use a single process, then breakpoints work normally.
How do I see the full Python traceback for an Odoo error in the browser?
Open browser DevTools → Network tab. Find the failing RPC request to /web/dataset/call_kw. In the response JSON, look at error.data.debug — it contains the full server-side traceback including file names and line numbers.
How do I debug a cron job that fails silently?
Go to Technical → Automation → Scheduled Actions, open the failing cron, and check the Log Notes chatter. Alternatively, run the cron method manually in the Odoo shell and watch for exceptions: env['ir.cron'].browse(cron_id).method_direct_trigger().
What log level should I use in production?
Use warn in production to minimize disk I/O and log noise. Switch to info or debug temporarily when investigating a specific issue, then revert. Debug logging on a busy instance generates gigabytes of logs per hour.
How do I find which XML ID corresponds to a record in the UI?
With developer mode active, open the record's form view and look at the URL — it contains the record ID. Then query: env['ir.model.data'].search([('res_id', '=', record_id), ('model', '=', 'model.name')]) in the shell to find the XML ID.
Debug Confidently on a Stable Platform
DeployMonkey gives you the tools to debug production issues safely: live log streaming, shell access, and one-click database snapshots before risky operations. View plans or start free today.