{"record":{"id":"cc51ff1a8c5535be","repo":"odoo/odoo","slug":"move-s-reached-an-invalid-state-regarding-its-re","errorCode":null,"errorMessage":"%(move)s reached an invalid state regarding its related statement line.\\nTo be consistent, the journal entry must always have exactly one suspense line.","messagePattern":"(.+?) reached an invalid state regarding its related statement line\\.\\\\nTo be consistent, the journal entry must always have exactly one suspense line\\.","errorType":"exception","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"addons/account/models/account_bank_statement_line.py","lineNumber":751,"sourceCode":"\n                st_line_vals_to_write.update({\n                    'payment_ref': liquidity_lines.name,\n                    'partner_id': liquidity_lines.partner_id.id,\n                })\n\n                # Update 'amount' according to the liquidity line.\n\n                if journal_currency:\n                    st_line_vals_to_write.update({\n                        'amount': liquidity_lines.amount_currency,\n                    })\n                else:\n                    st_line_vals_to_write.update({\n                        'amount': liquidity_lines.balance,\n                    })\n\n                if len(suspense_lines) > 1:\n                    raise UserError(_(\n                        \"%(move)s reached an invalid state regarding its related statement line.\\n\"\n                        \"To be consistent, the journal entry must always have exactly one suspense line.\",\n                        move=st_line.move_id.display_name,\n                    ))\n                elif len(suspense_lines) == 1:\n                    if journal_currency and suspense_lines.currency_id == journal_currency:\n\n                        # The suspense line is expressed in the journal's currency meaning the foreign currency\n                        # set on the statement line is no longer needed.\n\n                        st_line_vals_to_write.update({\n                            'amount_currency': 0.0,\n                            'foreign_currency_id': False,\n                        })\n\n                    elif not journal_currency and suspense_lines.currency_id == company_currency:\n\n                        # Don't set a specific foreign currency on the statement line.","sourceCodeStart":733,"sourceCodeEnd":769,"githubUrl":"https://github.com/odoo/odoo/blob/1e661df964b1b264c9cef3ab28430d4785be3fda/addons/account/models/account_bank_statement_line.py#L733-L769","documentation":"Same synchronization method, next invariant: after classifying the move's lines, at most one line may hit the journal's suspense account (len(suspense_lines) > 1 raises). The suspense account is a temporary balancing account; multiple suspense lines on one statement-line move are an invalid intermediate state.","triggerScenarios":"Editing the move lines of a statement line so that two or more lines use the journal's suspense_account_id — e.g. manually adding a second suspense-account line or duplicating the counterpart line before reconciliation.","commonSituations":"Manual journal-entry edits that add lines on the suspense account; custom code writing suspense lines; partial reconciliation tooling leaving duplicate suspense counterparts.","solutions":["Reduce to a single suspense line: reconcile/replace the extra suspense lines with real counterpart accounts.","Edit the statement line itself (amount, partner) instead of hand-editing the generated move lines.","Cancel and re-create the statement line to regenerate a clean move if the entry is heavily modified."],"exampleFix":"# before\nenv['account.move.line'].create({\n    'move_id': st_line.move_id.id,\n    'account_id': journal.suspense_account_id.id, ...})  # 2nd suspense line\n# -> UserError\n\n# after (single counterpart: edit the statement line / reconcile the suspense line)\nst_line.write({'amount': corrected_amount})","handlingStrategy":"validation","validationCode":"def move_has_at_most_one_suspense_line(st_line):\n    liquidity, suspense, other = st_line._seek_for_lines()\n    return len(suspense) <= 1","typeGuard":null,"tryCatchPattern":"from odoo.exceptions import UserError\ntry:\n    move.write({'line_ids': line_commands})\nexcept UserError as e:\n    if 'exactly one suspense line' in str(e):\n        raise  # remove/replace extra suspense lines, then retry\n    raise","preventionTips":["Keep at most one suspense-account line per statement-line move; reconcile extras to real accounts.","Avoid adding manual lines on journal.suspense_account_id.","Recreate the statement line when the generated move needs structural changes."],"tags":["odoo","accounting","bank-statement","move-synchronization","suspense-account"],"backgroundTag":null,"analyzedSha":"1e661df964b1b264c9cef3ab28430d4785be3fda","analyzedAt":"2026-08-15T05:22:16.142Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}