{"record":{"id":"a313f37e322788a6","repo":"we-promise/sure","slug":"failed-to-set-current-balance-result-error","errorCode":null,"errorMessage":"Failed to set current balance: #{result.error}","messagePattern":"Failed to set current balance: #(.+?)","errorType":"exception","errorClass":"EnableBankingAccount::Processor::ProcessingError","httpStatus":null,"severity":"error","filePath":"app/models/enable_banking_account/processor.rb","lineNumber":89,"sourceCode":"\n      currency = parse_currency(enable_banking_account.currency) || account.currency || \"EUR\"\n\n      # Wrap both writes in a transaction so a failure on either rolls back both.\n      ActiveRecord::Base.transaction do\n        if account.accountable.present? && account.accountable.respond_to?(:available_credit=)\n          account.accountable.update!(available_credit: available_credit)\n        end\n\n        if skip_balance_update\n          account.update!(currency: currency)\n        else\n          account.update!(currency: currency, cash_balance: balance)\n\n          # Use set_current_balance to create a current_anchor valuation entry.\n          # This enables Balance::ReverseCalculator, which works backward from the\n          # bank-reported balance — eliminating spurious cash adjustment spikes.\n          result = account.set_current_balance(balance)\n          raise ProcessingError, \"Failed to set current balance: #{result.error}\" unless result.success?\n        end\n      end\n\n      # TODO: pass explicit window_start_date to sync_later to avoid full history recalculation on every sync\n      # Currently relies on set_current_balance's implicit sync trigger; window params would require refactor\n    end\n\n    # Interprets the reported credit card balance based on the\n    # treat_balance_as_available_credit flag.\n    # Returns [balance, available_credit, skip_balance_update].\n    def interpret_credit_card_balance(account, reported_balance)\n      if enable_banking_account.treat_balance_as_available_credit?\n        # In this mode the accountable's available_credit field holds the credit\n        # limit: the API-provided one, or a user-entered value when the API\n        # omits it. Writing the limit back (never the reported balance) keeps\n        # the field stable across syncs so a manual limit is never clobbered.\n        credit_limit = positive_credit_limit(enable_banking_account.credit_limit) ||\n                       positive_credit_limit(account.accountable&.available_credit)","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/enable_banking_account/processor.rb#L71-L107","documentation":"EnableBankingAccount::Processor raises ProcessingError when account.set_current_balance(balance) returns an unsuccessful Result. set_current_balance (Account::CurrentBalanceManager#set_current_balance) wraps ANY internal exception into Result(error: e.message) — typical root causes are reconciliation/valuation creation failures or the cache write account.update!(balance:) failing.","triggerScenarios":"During an Enable Banking account import, after account.update!(currency:, cash_balance:), the current-balance manager fails: reconcile_balance or opening-balance delta adjustment raises (invalid amount/date, entry validation), or account.update! trips a validation; the manager converts it to a failed Result, and the processor re-raises as ProcessingError with that message.","commonSituations":"Bank-reported balances that violate entry validations; accounts in inconsistent state (missing currency/family, conflicting valuations); DB constraints on entries; unusual provider balance values on credit cards.","solutions":["Read the interpolated result.error — it carries the original exception message from CurrentBalanceManager#set_current_balance","Reproduce in console: account.set_current_balance(balance) on the failing account and inspect account.errors.full_messages and the raised cause","Fix the underlying record state (currency, existing valuations, missing associations) that makes valuation/reconciliation creation fail","For credit-card accounts, verify treat_balance_as_available_credit handling in interpret_credit_card_balance — the skip_balance_update path exists precisely to avoid bad balance writes"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"result = account.set_current_balance(balance)\nresult.success? # check before the processor raises; result.error carries the root cause","typeGuard":null,"tryCatchPattern":"rescue EnableBankingAccount::Processor::ProcessingError => e; e.message embeds the CurrentBalanceManager error — log it with DebugLogEntry (category 'enable_banking') so partial syncs are diagnosable","preventionTips":["Validate the account's base state (currency, family, existing valuations) before first sync","Check set_current_balance's Result instead of assuming success","For credit cards, verify treat_balance_as_available_credit so balances route to available_credit instead of failing cash writes"],"tags":["enable-banking","balance","processor","valuations"],"backgroundTag":"balance-update-failed","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}