odoo/odoo · error · ValidationError
A fiscal position with a foreign VAT already exists in this
Error message
A fiscal position with a foreign VAT already exists in this country.
What it means
Constraint on account.fiscal.position: at most one fiscal position per company may declare a given foreign_vat country. It counts sibling positions (same company domain, same country_id, any different foreign_vat value, excluding self) and raises ValidationError on duplicates, keeping the foreign-VAT registry unambiguous.
Source
Thrown at addons/account/models/partner.py:139
if record.foreign_vat:
if not record.country_id:
raise ValidationError(_("The country of the foreign VAT number could not be detected. Please assign a country to the fiscal position."))
if record.country_id == record.company_id.account_fiscal_country_id:
if not record.state_ids:
if record.company_id.account_fiscal_country_id.state_ids:
raise ValidationError(_("You cannot create a fiscal position with a foreign VAT within your fiscal country without assigning it a state."))
if record.country_group_id and record.country_id:
if record.country_id not in record.country_group_id.country_ids:
raise ValidationError(_("You cannot create a fiscal position with a country outside of the selected country group."))
similar_fpos_count = self.env['account.fiscal.position'].search_count([
*self.env['account.fiscal.position']._check_company_domain(record.company_id),
('foreign_vat', 'not in', (False, record.foreign_vat)),
('id', '!=', record.id),
('country_id', '=', record.country_id.id),
])
if similar_fpos_count:
raise ValidationError(_("A fiscal position with a foreign VAT already exists in this country."))
@api.onchange('country_id', 'foreign_vat')
def _onchange_foreign_vat(self):
self.foreign_vat, _country_code = self.env['res.partner']._run_vat_checks(self.country_id, self.foreign_vat, validation=False)
def _inverse_foreign_vat(self):
for record in self:
if not record.foreign_vat:
continue
if record.country_id:
fp_label = _("fiscal position [%s]", record.name)
record.foreign_vat, _country_code = self.env['res.partner']._run_vat_checks(record.country_id, record.foreign_vat, partner_name=fp_label)
def map_tax(self, taxes):
if not self:
return taxes
if not self.tax_ids:View on GitHub (pinned to 1e661df964)
Solutions
- Reuse the existing fiscal position for that country (update its tax/account mappings) instead of creating another.
- Delete or archive the obsolete duplicate, then save the new one.
- Dedupe in imports: search_count first, and skip when a position for that country exists.
Example fix
# before
env['account.fiscal.position'].create({'name': 'DE 2', 'country_id': de.id, 'foreign_vat': 'DE987'}) # ValidationError
# after
existing = env['account.fiscal.position'].search([
('company_id', '=', company.id), ('country_id', '=', de.id),
('foreign_vat', '!=', False)], limit=1)
fpos = existing or env['account.fiscal.position'].create({...}) Defensive patterns
Strategy: validation
Validate before calling
def no_duplicate_fpos(env, company, country_id, exclude_id=None):
return not env['account.fiscal.position'].search_count([
*env['account.fiscal.position']._check_company_domain(company),
('foreign_vat', 'not in', (False, False)),
('id', '!=', exclude_id), ('country_id', '=', country_id)]) Prevention
- Search for an existing same-country foreign-VAT position before creating one.
- Make onboarding wizards idempotent (reuse instead of duplicate).
When it happens
Trigger: create()/write() producing a second account.fiscal.position with the same country_id and a foreign_vat, in the same company; e.g. adding 'DE VAT #2' when 'DE VAT' already exists.
Common situations: Duplicate onboarding runs creating positions per registration; imports re-run without dedupe; two users creating the same foreign registration concurrently.
Related errors
- The country of the foreign VAT number could not be detected.
- You cannot create a fiscal position with a foreign VAT withi
- You cannot create a fiscal position with a country outside o
- You cannot remove/deactivate the accounts "%s" which are set
- This entry contains taxes that are not compatible with your
AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15).
Data as JSON: /api/errors/760b1d5c941e2508.
Report an issue: GitHub.