{"record":{"id":"e40849d897bdac91","repo":"we-promise/sure","slug":"class-name-item-unlinker-failed-to-fully-un","errorCode":null,"errorMessage":"<%= class_name %>Item Unlinker: failed to fully unlink provider account ##{provider_account.id} (links=#{link_ids.inspect}): #{e.class} - #{e.message}","messagePattern":"<%= class_name %>Item Unlinker: failed to fully unlink provider account ##(.+?) \\(links=#(.+?)\\): #(.+?) - #(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"lib/generators/provider/family/templates/unlinking_concern.rb.tt","lineNumber":39,"sourceCode":"      }\n      results << result\n\n      next if dry_run\n\n      begin\n        ActiveRecord::Base.transaction do\n          # Detach holdings for any provider links found\n          if link_ids.any?\n            Holding.where(account_provider_id: link_ids).update_all(account_provider_id: nil)\n          end\n\n          # Destroy all provider links\n          links.each do |ap|\n            ap.destroy!\n          end\n        end\n      rescue StandardError => e\n        Rails.logger.warn(\n          \"<%= class_name %>Item Unlinker: failed to fully unlink provider account ##{provider_account.id} (links=#{link_ids.inspect}): #{e.class} - #{e.message}\"\n        )\n        # Record error for observability; continue with other accounts\n        result[:error] = e.message\n      end\n    end\n\n    results\n  end\nend\n","sourceCodeStart":21,"sourceCodeEnd":50,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/lib/generators/provider/family/templates/unlinking_concern.rb.tt#L21-L50","documentation":"Generated unlinking concern processes each provider account of an item being unlinked: inside a transaction it nils out holdings referencing the account_provider links (update_all) and destroys each link. On StandardError the transaction rolls back for that account, the warning is logged with the account id and link ids, result[:error] records the message, and processing continues with remaining accounts — so an unlink operation can end partially complete for multi-account items.","triggerScenarios":"Holding.update_all hitting a lock/statement timeout while a sync job concurrently touches holdings; ap.destroy! raising ActiveRecord::RecordNotDestroyed when account_provider destroy callbacks veto deletion; DB constraint or serialization failures inside the transaction (unlinking_concern.rb.tt:39 region).","commonSituations":"User unlinks an item while a background sync is running against the same holdings; association callbacks (on account_provider) raising after customization; long-running transactions causing deadlocks under load.","solutions":["Read the account id and e.class/e.message from the log, then check that account's holdings and account_provider rows — a rolled-back transaction leaves both untouched","Retry the unlink for the affected provider account once the concurrent sync job finishes (per-account processing makes partial retries safe)","Audit account_provider destroy callbacks for raises; make them non-blocking or ensure they only fire on intentional destroys","If lock contention recurs, shrink the transaction or add WITH LOCK timeouts / retry logic around the unlink"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# Before unlinking, confirm no concurrent sync is running against these holdings\nlinks.each do |ap|\n  next unless ap.persisted? && ap.account.present? # skip already-removed links\nend\nHolding.where(account_provider_id: link_ids).update_all(account_provider_id: nil)","typeGuard":null,"tryCatchPattern":"rescue ActiveRecord::Deadlocked, ActiveRecord::LockWaitTimeout => e\n  # transient contention with a running sync - safe to retry per account later\n  result[:error] = \"lock-timeout:#{e.class}\"\nrescue StandardError => e\n  Rails.logger.warn(\"... failed to fully unlink provider account ##{provider_account.id} (links=#{link_ids.inspect}): #{e.class} - #{e.message}\")\n  result[:error] = e.message\nend","preventionTips":["Run unlinks per-account in small transactions (as the template does) so one failure can't roll back the whole item unlink","Check the results array for :error entries after unlink operations and retry just the failed account ids","Avoid unlinking while sync jobs for the same item are enqueued, or make destroy! callbacks non-raising"],"tags":["unlinking","transaction-rollback","partial-failure","generator-template","locks","background-jobs"],"backgroundTag":"partial-bulk-operation-failure","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}