{"record":{"id":"c2b6fd94740411da","repo":"odoo/odoo","slug":"you-cannot-use-an-archived-account","errorCode":null,"errorMessage":"You cannot use an archived account.","messagePattern":"You cannot use an archived account\\.","errorType":"exception","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"addons/account/models/account_move_line.py","lineNumber":1819,"sourceCode":"                        line.move_id._message_log(\n                            body=_(\"Journal Item %s created\", line._get_html_link(title=f\"#{line.id}\")),\n                            tracking_value_ids=tracking_value_ids\n                        )\n\n        lines.move_id._synchronize_business_models(['line_ids'])\n        # Remove analytic lines created for draft AMLs, after analytic_distribution has been updated\n        lines.filtered(lambda l: l.parent_state == 'draft').analytic_line_ids.with_context(skip_analytic_sync=True).unlink()\n        return lines\n\n    def write(self, vals):\n        if not vals:\n            return True\n        protected_fields = self._get_lock_date_protected_fields()\n        account_to_write = self.env['account.account'].browse(vals['account_id']) if 'account_id' in vals else None\n\n        # Check writing a archived account.\n        if account_to_write and not account_to_write.active:\n            raise UserError(_('You cannot use an archived account.'))\n\n        inalterable_fields = set(self._get_integrity_hash_fields()).union({'inalterable_hash'})\n        hashed_moves = self.move_id.filtered('inalterable_hash')\n        violated_fields = set(vals) & inalterable_fields\n        if hashed_moves and violated_fields:\n            raise UserError(_(\n                \"You cannot edit the following fields: %(fields)s.\\n\"\n                \"The following entries are already hashed:\\n%(entries)s\",\n                fields=[f['string'] for f in self.fields_get(violated_fields).values()],\n                entries='\\n'.join(hashed_moves.mapped('name')),\n            ))\n\n        line_to_write = self\n        vals = self._sanitize_vals(vals)\n        matching2lines = None  # lazy cache\n        lines_to_unreconcile = self.env['account.move.line']\n        st_lines_to_unreconcile = self.env['account.bank.statement.line']\n        tax_lock_check_ids = []","sourceCodeStart":1801,"sourceCodeEnd":1837,"githubUrl":"https://github.com/odoo/odoo/blob/1e661df964b1b264c9cef3ab28430d4785be3fda/addons/account/models/account_move_line.py#L1801-L1837","documentation":"Raised in account.move.line.write(): before applying the write, if vals contains 'account_id' pointing to an account whose active flag is False, the write is refused outright with this UserError. Unlike the constraint-based check (error 104), this is a fast-path guard in write() itself with no is_imported/context escape — any programmatic assignment of an archived account fails.","triggerScenarios":"Calling write({'account_id': <id>}) (or any vals dict including account_id) on account.move.line records where the browsed account.account row has active=False. Common in scripts that move lines between accounts, apply fiscal position remappings, or import mappings resolved by account code where the code now belongs to an archived account.","commonSituations":"Chart cleanups archiving accounts that external integrations still reference by ID/code; migration tools remapping old account codes; scheduled server actions reassigning accounts; partner property fields pointing to archived accounts applied via write.","solutions":["Resolve the target account by code/xml_id among ACTIVE accounts only (search([('code','=',code),('active','in',[True,False])]) then check active, or filter active in the domain).","Un-archive the intended account before the write if it must be used again.","If the account was archived on purpose, pick its replacement account (maintain a mapping old->new) and use that in the write."],"exampleFix":"# before\nline.write({'account_id': account_by_code.id})\n\n# after\naccount = self.env['account.account'].search([('code', '=', code), ('company_id', '=', company.id), ('active', '=', True)], limit=1)\nif not account:\n    raise UserError(_(\"No active account with code %s\", code))\nline.write({'account_id': account.id})","handlingStrategy":"validation","validationCode":"account = self.env['account.account'].browse(vals['account_id'])\nif 'account_id' in vals and not account.active:\n    replacement = self.env['account.account'].search([\n        ('code', '=', account.code),\n        ('company_id', '=', account.company_id.id),\n        ('active', '=', True),\n    ], limit=1)\n    vals['account_id'] = replacement.id if replacement else account.id\n    if not replacement:\n        account.write({'active': True})","typeGuard":"def account_is_usable(account):\n    \"\"\"An account usable on journal items must be active.\"\"\"\n    return bool(account) and account.active","tryCatchPattern":"from odoo.exceptions import UserError\ntry:\n    line.write({'account_id': account.id})\nexcept UserError as e:\n    if 'archived account' in str(e):\n        account.write({'active': True})  # or map to a replacement account\n        line.write({'account_id': account.id})\n    else:\n        raise","preventionTips":["Resolve accounts with active=True in the search domain in all integrations.","Maintain an archived->replacement account mapping for chart cleanups.","Before archiving accounts, verify no scheduled actions or external feeds still reference their IDs."],"tags":["accounting","archived","write","orm","usererror"],"backgroundTag":null,"analyzedSha":"1e661df964b1b264c9cef3ab28430d4785be3fda","analyzedAt":"2026-08-15T05:22:16.142Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}