Skip to content

Odoo Cron Jobs Not Running? Complete Troubleshooting Guide

DeployMonkey Team · March 22, 2026 12 min read

Symptoms

  • Emails stuck in queue (not being sent)
  • Subscriptions not renewing
  • Inventory rules not triggering
  • Automated actions not firing
  • Scheduled reports not generating

Cause 1: workers=0 (Most Common)

# In single-thread mode (workers=0), cron jobs share
# the same thread as HTTP requests.
# If the server is busy, crons may not run.

# Fix: enable multi-process mode
# odoo.conf:
workers = 5  # (CPU × 2) + 1

# With workers > 0, Odoo spawns a dedicated cron worker
# that processes scheduled actions independently

Cause 2: Cron Disabled

# Check if the specific cron is active:
SELECT name, active, interval_number, interval_type,
       lastcall, nextcall, numbercall
FROM ir_cron
WHERE name LIKE '%Email%';

# If active = false:
UPDATE ir_cron SET active = true WHERE id = XXX;

# If numbercall = 0 (exhausted its run count):
UPDATE ir_cron SET numbercall = -1 WHERE id = XXX;
# -1 means unlimited runs

# In Odoo UI:
# Settings → Technical → Scheduled Actions
# Find the cron → check Active checkbox
# Set Number of Calls to -1 (unlimited)

Cause 3: Cron Crashed and Stopped

# If a cron throws an unhandled exception, it may stop running.
# Check the Odoo log for errors:
grep -i "cron" /var/log/odoo/odoo.log | grep -i "error" | tail -20

# Common cron errors:
# - AccessError (permissions changed)
# - RecordNotFoundError (deleted record referenced)
# - ConnectionError (external API down)
# - MemoryError (cron processing too much data)

# Fix: fix the error in the cron code, then reactivate

Cause 4: Database Lock

# Another process holds a lock that blocks the cron:
SELECT pid, state, query, now() - query_start as duration
FROM pg_stat_activity
WHERE datname = 'odoo' AND state != 'idle'
ORDER BY duration DESC;

# Check for advisory locks (used by some crons):
SELECT * FROM pg_locks WHERE locktype = 'advisory';

# Fix: terminate the blocking query
SELECT pg_terminate_backend(PID);

Cause 5: nextcall Far in the Future

# The cron's next execution time is set far in the future:
SELECT name, nextcall FROM ir_cron
WHERE nextcall > NOW() + INTERVAL '1 day'
ORDER BY nextcall;

# Fix: reset nextcall to now
UPDATE ir_cron SET nextcall = NOW() WHERE id = XXX;

Cause 6: Time Zone Issues

# Odoo stores cron times in UTC.
# If your server timezone changed, nextcall may be off.

# Check server timezone:
timedatectl

# Odoo should always run in UTC:
# odoo.conf or systemd service:
# Environment="TZ=UTC"

Cause 7: max_cron_threads

# In Odoo 16+, max_cron_threads controls how many crons run simultaneously
# Default: 2
# If you have many crons, increase:

# odoo.conf:
max_cron_threads = 4

Diagnosis Checklist

  1. Check workers in odoo.conf — must be > 0 for reliable crons
  2. Check active and numbercall in ir_cron table
  3. Check Odoo logs for cron errors
  4. Check lastcall — is it recent or stuck in the past?
  5. Check nextcall — is it in the future or past?
  6. Check for database locks blocking execution
  7. Check server timezone — should be UTC
  8. Restart Odoo and monitor logs

Monitoring Cron Health

# Alert if any cron hasn't run in 2× its interval:
SELECT name, lastcall, nextcall,
       interval_number || ' ' || interval_type as interval,
       CASE WHEN lastcall < NOW() - (interval_number * 
           CASE interval_type 
               WHEN 'minutes' THEN INTERVAL '1 minute'
               WHEN 'hours' THEN INTERVAL '1 hour'
               WHEN 'days' THEN INTERVAL '1 day'
           END * 2)
       THEN 'STUCK' ELSE 'OK' END as status
FROM ir_cron
WHERE active = true;

DeployMonkey

DeployMonkey's AI agent monitors cron health automatically. It detects stuck crons, identifies the root cause (disabled, error, lock), and alerts you with the specific fix. Cron issues are diagnosed in seconds, not hours.