odoo/odoo · error · UserError

You cannot modify the taxes related to a posted journal item

Error message

You cannot modify the taxes related to a posted journal item, you should reset the journal entry to draft to do so.

What it means

account.move.line.write() refuses to change tax_ids or tax_line_id on a line whose parent move is in state 'posted'. Tax fields on posted entries are immutable because they affect the tax report and legal figures; you must first reset the entry to draft.

Source

Thrown at addons/account/models/account_move_line.py:1844

                "You cannot edit the following fields: %(fields)s.\n"
                "The following entries are already hashed:\n%(entries)s",
                fields=[f['string'] for f in self.fields_get(violated_fields).values()],
                entries='\n'.join(hashed_moves.mapped('name')),
            ))

        line_to_write = self
        vals = self._sanitize_vals(vals)
        matching2lines = None  # lazy cache
        lines_to_unreconcile = self.env['account.move.line']
        st_lines_to_unreconcile = self.env['account.bank.statement.line']
        tax_lock_check_ids = []
        for line in self:
            if not any(self.env['account.move']._field_will_change(line, vals, field_name) for field_name in vals):
                line_to_write -= line
                continue

            if line.parent_state == 'posted' and any(self.env['account.move']._field_will_change(line, vals, field_name) for field_name in ('tax_ids', 'tax_line_id')):
                raise UserError(_('You cannot modify the taxes related to a posted journal item, you should reset the journal entry to draft to do so.'))

            # Check the lock date.
            if line.parent_state == 'posted' and any(self.env['account.move']._field_will_change(line, vals, field_name) for field_name in protected_fields['fiscal']):
                line.move_id._check_fiscal_lock_dates()

            # Check the tax lock date.
            if line.parent_state == 'posted' and any(self.env['account.move']._field_will_change(line, vals, field_name) for field_name in protected_fields['tax']):
                tax_lock_check_ids.append(line.id)

            # Break the reconciliation.
            if (
                line.matching_number
                and (changing_fields := {
                    field_name
                    for field_name in protected_fields['reconciliation']
                    if self.env['account.move']._field_will_change(line, vals, field_name)
                })
            ):

View on GitHub (pinned to 1e661df964)

Solutions

  1. Call move.button_draft() first, apply the tax change, then re-post with move.action_post().
  2. If the move is locked by a lock date, move the lock date or post a correcting credit note instead.
  3. For code paths that must not unpost, filter out posted lines and report them instead of writing (see validation snippet).

Example fix

// before
invoice.line_ids.write({'tax_ids': [(6, 0, [tax.id])]})  # UserError if posted

// after
if invoice.state == 'posted':
    invoice.button_draft()
invoice.line_ids.write({'tax_ids': [(6, 0, [tax.id])]})
invoice.action_post()
Defensive patterns

Strategy: validation

Validate before calling

tax_vals = {k: vals[k] for k in ('tax_ids', 'tax_line_id') if k in vals}
if tax_vals and line.parent_state == 'posted':
    line.move_id.button_draft()
line.write(vals)

Prevention

When it happens

Trigger: write({'tax_ids': [...]}) or write({'tax_line_id': id}) on an account.move.line with line.parent_state == 'posted', where _field_will_change() confirms the value actually differs. Common from UI edits, API imports, or code applying a manual tax after posting.

Common situations: Fixing a wrong tax on a posted invoice from a custom script; syncing tax changes from an external system into posted Odoo entries; onchange-side effects trying to recompute tax lines while the move stays posted.

Related errors


AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15). Data as JSON: /api/errors/2c1fe7307ac2dbde. Report an issue: GitHub.