Saltar al contenido principal

Actualización de Odoo cancelada Base de datos dañada - Guía de recuperación

¿La actualización de Odoo se canceló con un error de base de datos dañada? Recuperación paso a paso mediante reversión, actualización abierta y reconstrucción del registro para el 18/17/19 en producción.

E
ECOSIRE Research and Development Team
|4 de mayo de 20267 min de lectura1.3k Palabras|

Este artículo actualmente está disponible solo en inglés. La traducción estará disponible próximamente.

Halfway through an Odoo upgrade — typically 17.0 to 18.0 or 18.0 to 19.0 — the process aborts and the log ends with something like:

Halfway through an Odoo upgrade — typically 17.0 to 18.0 or 18.0 to 19.0 — the process aborts and the log ends with something like:

ERROR: integrity violation in module 'sale_subscription'
ERROR: upgrade aborted, database state may be corrupted

The server will not start. Workers crash on registry load. Users are locked out. This is the worst-case Odoo upgrade failure, and the recovery has a specific order. Skipping a step turns a 2-hour outage into a 2-day outage. This guide is the playbook ECOSIRE's Odoo migration team uses on every escalation.

Quick Fix

Stop. Do not retry the upgrade. Restore from the pre-upgrade backup and start over with proper preparation:

sudo systemctl stop odoo
sudo -u postgres dropdb <db>
sudo -u postgres createdb <db> -O odoo
sudo -u postgres pg_restore -d <db> /backups/pre-upgrade-snapshot.dump
sudo systemctl start odoo

Now the database is at its pre-upgrade state. Diagnose what went wrong before re-attempting. Re-running -u all against a half-upgraded database compounds the corruption.

Why This Happens

The Odoo upgrade pipeline is a long-running, multi-module transaction. When it aborts mid-way, it leaves behind:

  1. Half-migrated tables. Some columns renamed, others not. Some constraints dropped, others still present.
  2. Mixed module states. ir_module_module shows half the modules at the new version, half at the old.
  3. Disabled views and broken ir_model_data. XML IDs that point at fields that have been renamed.
  4. Foreign-key violations. Migration scripts often disable FKs, migrate data, re-enable. If the abort happens between, FK constraints remain unenforced.
  5. Inconsistent ir_attachment web assets. Frontend asset bundles reference fields that no longer exist.

The five common root causes:

  • Custom module migration script raised an exception. A migrations/<v>/post-migration.py file that assumed a column existed.
  • Out-of-memory. Large migrations (millions of rows in mail.message or account.move.line) OOM the worker partway.
  • Disk full. PostgreSQL ran out of space for the WAL log.
  • Network blip. Odoo lost the database connection during a long migration.
  • Manual interruption. Someone Ctrl+C'd the upgrade because it "was taking too long".

Step-by-Step Diagnosis

1. Get the full upgrade log. Find the abort line and read backwards 200 lines. The first warning or error is the actual cause; the abort itself is just the symptom.

2. Check the OS-level signals.

journalctl -u odoo --since "2 hours ago" | grep -E "(killed|memory|signal)"
dmesg | grep -i "killed process"

OOM-killer entries in dmesg are dispositive — your worker ran out of RAM.

3. Check disk and WAL state.

df -h /var/lib/postgresql
sudo -u postgres psql -c "SELECT pg_walfile_name(pg_current_wal_lsn());"

Disk above 95 percent or WAL pile-up tells you to fix the storage layer before retrying.

4. Inventory transitional modules.

SELECT name, state, latest_version
FROM   ir_module_module
WHERE  state IN ('to upgrade', 'to install', 'to remove');

This is your mid-flight cargo manifest. The first module in this list is usually where the abort happened.

5. Check transaction log of the migration.

grep "migrations" /var/log/odoo/odoo.log | tail -50

The last Loading migrations/<v>/<phase> line tells you exactly which script blew up.

Permanent Fix

Step 1 — Restore. Always restore from the pre-upgrade snapshot before doing anything else. Never patch a half-upgraded database. The diagnostic findings tell you what to fix on the restored copy before trying again.

Step 2 — Fix the root cause.

  • Custom migration script error: read the script, find the assumption (usually "this column exists"), fix it. Test on a restored copy.
  • OOM: increase limit_memory_hard and limit_memory_soft in odoo.conf, add swap, or split the migration into batches. Long migrations sometimes need --workers=0 --max-cron-threads=0 to give the entire process maximum memory.
  • Disk full: add storage. PostgreSQL needs roughly 2x the database size in free WAL space for a major upgrade.
  • Network blip: run the upgrade on the database server itself (or via a stable VPN session, not a shaky SSH tunnel).
  • Manual interruption: explain to the team that Odoo upgrades take what they take. Document an SLO ("Sale orders module always takes 45 minutes") so people stop interrupting.

Step 3 — Pre-upgrade dry run. With the cause fixed, restore a fresh copy and dry-run:

sudo -u odoo /opt/odoo/odoo-bin -c upgrade.conf \
  -d <staging-db> -u all --stop-after-init --no-http \
  --logfile=/var/log/odoo/upgrade-dry-run.log

Read the entire log even if exit code is 0. Warnings during dry-run become aborts during production.

Step 4 — Real upgrade with safeguards. When dry-run is clean, run the production upgrade with checkpoint commits:

# Use openupgrade's checkpoint tooling for major versions
pip install openupgradelib
sudo -u odoo /opt/odoo/odoo-bin -c production.conf \
  -d <db> -u all --stop-after-init --no-http

Always tail the log. Always have the rollback pg_restore command ready in another terminal.

Step 5 — Post-upgrade verification.

SELECT count(*) FROM ir_module_module
WHERE state IN ('to upgrade', 'to install', 'to remove');

This must be 0. Then run click-odoo-update -d <db> to catch lingering drift, and run a smoke test on every critical workflow before re-opening to users.

How to Prevent It

  • Backup is non-negotiable. Every Odoo production database needs daily pg_dump plus continuous WAL archiving. Before any upgrade, an additional fresh full backup. ECOSIRE production deploys gate on Step 3 (pre-deploy-backup.cjs) — no backup, no deploy.
  • Always dry-run on staging first. A staging database identical to production catches every migration script bug. The 2-hour staging cost saves a 12-hour production outage every time.
  • Don't custom-write migration scripts unless you must. OCA's openupgrade ships scripts for every official module's renames and field changes. Use them.
  • Memory and disk plan. Know your DB size, double it, ensure you have headroom. Increase limit_memory_* for the upgrade pass.
  • Maintenance window communication. Set expectations with the team. Major Odoo upgrades take hours, not minutes. Plan for it. Plan for double if it is the first major version jump in two years.
  • Run from the DB server. The single biggest cause of "upgrade aborted" we see at ECOSIRE is a flaky network connection between the upgrade host and the database. SSH to the DB server (or its bastion) and run from there.

Frequently Asked Questions

Can I just retry -u all on the half-upgraded database?

No. The half-upgraded state has invalid foreign keys, partial column renames, and inconsistent ir_module_module rows. Retrying compounds the corruption. Restore, fix, retry against the clean snapshot.

How long should a major version upgrade take?

Highly variable. A small Odoo (5 GB DB, 20 modules, no Studio) upgrades in 20 minutes. A typical production system (50 GB DB, 60 modules, Studio in use) takes 2 to 4 hours. Add an hour for asset rebuild and verification. If your dry-run took 30 minutes, expect production to take 30 to 45 minutes.

Is pg_dump the right backup format for upgrades?

Use pg_dump -Fc (custom format) or pg_basebackup plus WAL archives. Plain SQL dumps are fine but slow to restore on large databases. Custom format restores in parallel with pg_restore -j 4. For databases over 100 GB, pg_basebackup is the only sane option.

Should I upgrade through every intermediate version (17 → 18 → 19) or jump directly?

Always go through the intermediates. Odoo's upgrade scripts are written assuming each version is the source. Jumping versions means writing custom migration scripts to bridge the gap. The intermediate path is slower in wall time but vastly safer in risk and effort. ECOSIRE's Odoo migration team does it this way for every customer.


Need help with a tricky Odoo error? ECOSIRE's Odoo experts have shipped 215+ modules — get expert help.

Compartir:
E

Escrito por

ECOSIRE Research and Development Team

Redacción técnica

El equipo de redacción técnica de ECOSIRE escribe sobre Odoo ERP, comercio electrónico con Shopify, agentes de IA, analítica con Power BI, automatización con GoHighLevel y buenas prácticas de software empresarial. Nuestras guías ayudan a las empresas a tomar decisiones tecnológicas informadas.

ECOSIRE

Transforme su negocio con Odoo ERP

Implementación, personalización y soporte experto de Odoo para optimizar sus operaciones.