Common errors migrating Odoo 17/18 to 19
Migrating from Odoo 17 or 18 to 19 isn't a one-click job. Here are the failures that actually show up — removed APIs, broken custom modules, data integrity issues and view changes — with the error message and how to fix it.
Before you start: the rule that breaks almost every migration
Odoo doesn't support version-skipping. The migration is sequential:
17 to 18, and 18 to 19. Both the official
upgrade.odoo.com service and
OpenUpgrade (the OCA's free tool) work step by step.
If you load a 17 dump onto a 19 server and run -u all,
modules end up stuck in a to upgrade state without actually migrating, and the data gets corrupted.
The second rule: always work on a copy. Restore the backup to a test database, migrate there, validate, and only then plan the real one. A trial migration is also the only honest way to estimate the effort your custom code will take.
1. Removed APIs and attributes
This is error number one. The attrs="{...}" and
states="..." attributes were removed in Odoo 17, and 19 no longer tolerates
any leftover trace of them. Any inherited view that still uses them blows up when the module loads.
ParseError: Since 17.0, the "attrs" and "states" attributes are no longer used.
Fix: replace them with direct attributes
invisible, readonly and required using Python
expressions: invisible="state != 'draft'" instead of
attrs="{'invisible': [('state','!=','draft')]}".
Methods that had been deprecated for years get removed with every major version. The typical ones:
name_get() (replaced by _compute_display_name),
fields_view_get() (now get_view()), and changes to the signatures of
_default_get or onchange methods.
AttributeError: 'res.partner' object has no attribute 'name_get'
Fix: review the release notes and the deprecation commit for each version. OpenUpgrade documents model changes in its scripts folder, but your own code that calls those methods has to be adapted by hand — there's no automated way to do it.
Since Odoo 17 the frontend is pure OWL and the assets system uses JS module
imports (/** @odoo-module **/) instead of
odoo.define. An old widget that still uses the old pattern or calls
require('web.core') stops loading and the view is left blank.
UncaughtPromiseError: Failed to load resource / Cannot read properties of undefined
Fix: rewrite the component with the OWL API,
declare the assets in web.assets_backend in the manifest and remove
any odoo.define. This is by far the most expensive part to migrate if you have
a lot of custom UI.
2. Custom and third-party modules that won't install
If your module's manifest declares a depends on an OCA addon
(for example queue_job, web_responsive or some
account_* module) that doesn't have a published 19.0 branch yet, the install
stops dead. 19 is recent, and many OCA repos take months to be ported.
odoo.exceptions.ValidationError: Unable to install module "X" because an external dependency is not met
Fix: before migrating, take inventory of all your
depends and check on GitHub whether a 19.0 branch exists. If it doesn't,
you have three options: wait for the port, port it yourself (and contribute it back), or drop
the dependency. This is what surprises people coming from a standard Enterprise setup the most.
Forgetting to bump the version key in the manifest to 19.0.x.y.z makes
Odoo assume the module hasn't changed and skip the migration scripts.
The module "installs" but the data is left half-updated, which is more dangerous
than a visible error.
Fix: start the module's version number with the Odoo
version (19.0.1.0.0), bump the suffix on every change that ships a migration
script, and check the logs for a Loading migration script line.
3. Data integrity
Data problems are the most silent ones and the ones that cause the most pain in production. They show up when the "old" database has records that 19 no longer allows, or when a field changes type or becomes mandatory between versions.
- New NOT NULL constraints: a field that was optional in 17
and is mandatory in 19 breaks the migration if there are rows with that value set to NULL.
The log shows
psycopg2.errors.NotNullViolation: null value in column "...". You need to fill in those records before migrating. - Orphaned foreign keys: references to deleted records that the
new version validates with a stricter
ON DELETE. They raise aForeignKeyViolationwhen stored fields are recomputed. - Stored fields that get recomputed:
computefields withstore=Trueare recomputed in bulk during migration; if the formula changed, invoice totals or stock levels can shift. Compare totals before and after. - Duplicate data that now breaks a unique constraint: new unique indexes (for example on product references) fail if you're carrying duplicates.
How to avoid it: clean the data in the source version (not the migrated one), and after each jump validate with control queries: number of accounting entries, sum of debits and credits, total open orders, stock valuation. If a number doesn't add up, don't move forward until you understand why.
4. View and interface changes
Even when the module installs fine, the interface can end up broken because the structure of the standard views changed and your inheritances can no longer find the node they're looking for with XPath.
Element '<xpath expr="//field[@name='...']">' cannot be located in parent view
Fix: the field was moved, renamed, or the form got reorganized. Open the standard view for 19, find the new node and adjust the XPath. Using fragile selectors (exact position) is what causes these failures; it's better to anchor to stable field names.
- The
<tree>tag was renamed to<list>in 17/18; inherited list views still using the old name may raise warnings or simply not apply. - Changes to the status bar and header buttons that break inheritances that inserted buttons by position.
- Odoo 19's new visual design can throw off custom widgets that assumed old widths or CSS classes.
OpenUpgrade or Odoo's official service?
There's no single answer. Here's the honest breakdown of each path, including the OCA's free option:
| Criterion | upgrade.odoo.com (official) | OpenUpgrade (OCA, free) |
|---|---|---|
| Cost | Included with Enterprise / Odoo.sh; paid for Community without a contract. | Free and open source (AGPL/LGPL depending on the repo). |
| Standard data | Very reliable, automated, supported by Odoo. | Reliable, but you run the server and the process yourself. |
| Custom modules | Doesn't migrate them: tells you to adapt them yourself. | Same: you have to write your own migration scripts. |
| Control and traceability | Partly a black box; you get the result. | Full control: you see every script that runs. |
| Availability for 19.0 | Available for supported versions. | Depends on how mature the 19.0 branch is; check before you rely on it. |
In both cases, the bulk of the work (and the real cost) is in adapting your own code and validating the data, not in running the tool. Anyone who promises an "automatic" migration for an installation with custom modules isn't being honest.
Minimum checklist before migrating to Odoo 19
- Inventory of all modules (standard, OCA, custom) and their
depends. - Check which OCA dependencies already have a 19.0 branch and which don't.
- Trial migration on a copy, jump by jump (17→18→19), never direct.
- Search and replace
attrs,states,name_getandodoo.definein your own code. - Data cleanup at the source: NULLs in future-mandatory fields, duplicates, orphaned FKs.
- Control queries on totals (accounting, stock, orders) before and after.
- Rollback plan: a verified, restorable backup before touching production.
Odoo 19 migration done by engineers
At FlexigoTech (Barcelona) we run the migration jump by jump, adapt your custom modules and validate data integrity. No middlemen, and a quote based on a real trial migration, not a promise.
See our migration and custom development serviceFAQ
Can you jump straight from Odoo 17 to 19?
Not in a supported way. Migration is sequential: 17 → 18 → 19. Loading a 17 dump onto a 19 server leaves modules stuck in a "to upgrade" state that never actually updates and breaks data integrity. You have to chain each jump and validate between them.
Why does my custom module no longer install?
The usual reasons: removed view attributes (attrs/states), retired ORM methods (name_get), old JS assets (odoo.define instead of OWL) and OCA dependencies without a 19.0 branch. It typically fails with a ParseError, KeyError or an external dependency ValidationError.
OpenUpgrade or Odoo's official service?
If you're on Online/Odoo.sh with standard modules, the official upgrade is the most convenient and supported option. If you're self-hosting Community or have custom code, OpenUpgrade from the OCA is free and open but requires writing your own scripts. Neither migrates your custom logic automatically.
How long does it take and how much does it cost?
It depends on how many custom modules you have and how clean the data is. A standard database migrates in days; one with many custom addons can take weeks. The cost is in reviewing and rewriting your own code. The honest approach is to run a trial migration first to estimate it.