Odoo upgrade error
could not create unique index "account_move_unique_name"
Last updated: November 2026
Two or more posted journal entries in the same journal have the same number, and the new Odoo version refuses to create its uniqueness index on top of them.
This page is part of our guide on how to upgrade Odoo Community Edition. It explains what triggers the error, how to fix it by hand, and what an automated migration does about it.
The error
psycopg2.errors.UniqueViolation: could not create unique index "account_move_unique_name"
DETAIL: Key (name, journal_id)=(INV/2024/00042, 1) is duplicated.The DETAIL line names the duplicated number and the journal id. Once the index exists, Odoo reports the same conflict to users as "Another entry with the same name already exists."
- Index
UNIQUE (name, journal_id) WHERE state = 'posted' AND name != '/'onaccount_move- Created by
account.move._auto_initin Odoo 17 and 18; amodels.UniqueIndexin Odoo 19 and 20- Seen when
- The
accountmodule loads during-u all, usually on the step to 17 or later
When you see it
Odoo 16 checks that a posted entry number is unique in Python (_check_unique_sequence_number), and only when a record is posted or renamed through the ORM. Odoo 17 moves the rule into PostgreSQL: account.move._auto_init creates a partial unique index on (name, journal_id) for posted entries whose name is not /. Odoo 19 declares the same index on the model. PostgreSQL checks every existing row when it builds the index, so one pair of posted entries with the same number in the same journal stops the whole upgrade.
Odoo 17 and 18 only create the index when it does not exist yet. A database that already has it cannot contain duplicates. You see the error when the index was never there (a database coming from 16) or was lost along the way, for example when a dump was restored and the index failed to build.
Root cause
Duplicates get past the Python check in a few common ways:
- Entries imported or created with SQL, or by a module that writes
namedirectly. - A journal sequence that was reset or edited, so new entries reused numbers that already existed.
- Entries moved between journals after posting, landing next to an entry with the same number.
How to fix it
List every duplicate, not just the one in the error. Odoo stops at the first, so fixing one at a time means one failed upgrade per duplicate:
SELECT journal_id, name, array_agg(id ORDER BY id) AS move_ids, count(*)
FROM account_move
WHERE state = 'posted' AND name != '/'
GROUP BY journal_id, name
HAVING count(*) > 1
ORDER BY journal_id, name;Entry numbers on customer invoices are legal documents in most countries, so decide with your accountant which entry keeps the number. Usually the oldest one keeps it and the others get a visible suffix. Amounts, lines and reconciliation stay as they are.
Before you change anything: Back up the database before running any UPDATE or INSERT below, and try it on a copy first. These statements change data directly, outside the Odoo ORM.
This keeps the lowest id as is and appends the record id to the others, the same format OpenUpgrade uses:
UPDATE account_move m
SET name = m.name || ' [' || m.id || ']'
FROM (
SELECT journal_id, name, min(id) AS keep_id
FROM account_move
WHERE state = 'posted' AND name != '/'
GROUP BY journal_id, name
HAVING count(*) > 1
) d
WHERE m.journal_id = d.journal_id
AND m.name = d.name
AND m.state = 'posted'
AND m.id != d.keep_id;Run the SELECT again to confirm it returns no rows, then restart the upgrade. The stored sequence_prefix and sequence_number columns are not recomputed by this update, and Odoo reads the next number from the latest entry in the journal: if a renamed entry is the most recent one, post a new entry in the old version first or check the next number after the upgrade. If the duplicates are supplier bills with numbers you typed in, you can also give them new numbers from the journal sequence in the old version before upgrading.
How OCU handles it
Before the 16→17 step loads Odoo 17, OCU renames duplicate posted entry numbers per journal the same way OpenUpgrade does: every entry in a duplicated group gets its id appended in square brackets, so the index can be created. Nothing is deleted and no amounts change. Search for [ in the entry numbers afterwards to find and review the renamed entries.
A free test migration shows whether your database runs into this or any other upgrade error before you change anything on your production server.
Frequently asked questions
- Will renaming a posted invoice break my accounting?
- No. Amounts, journal items, taxes and reconciliations stay the same; only the number changes. Check the next number in the journal afterwards, as described above. Because the number is printed on the document, keep the original number on the entry your customer received and add a suffix to the others.
- Why did Odoo 16 allow duplicates?
- Odoo 16 checks uniqueness in Python when an entry is posted or renamed through the ORM. Imports, SQL updates and sequence resets bypass that check. Odoo 17 and later enforce it with a database index, which PostgreSQL validates against every existing row.
- Do draft entries cause this error?
- No. The index only covers entries in state posted whose name is not '/'. Drafts and cancelled entries can share a number without blocking the upgrade.
Related
Find upgrade errors before your production run
Upload a backup and run a free test migration. You get the upgraded database, the full log and every warning, with no change to your live system.
Start your free test migration