we-promise/sure · warning
<%= class_name %>Item Unlinker: failed to fully unlink provi
Error message
<%= class_name %>Item Unlinker: failed to fully unlink provider account ##{provider_account.id} (links=#{link_ids.inspect}): #{e.class} - #{e.message} What it means
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.
Source
Thrown at lib/generators/provider/family/templates/unlinking_concern.rb.tt:39
}
results << result
next if dry_run
begin
ActiveRecord::Base.transaction do
# Detach holdings for any provider links found
if link_ids.any?
Holding.where(account_provider_id: link_ids).update_all(account_provider_id: nil)
end
# Destroy all provider links
links.each do |ap|
ap.destroy!
end
end
rescue StandardError => e
Rails.logger.warn(
"<%= class_name %>Item Unlinker: failed to fully unlink provider account ##{provider_account.id} (links=#{link_ids.inspect}): #{e.class} - #{e.message}"
)
# Record error for observability; continue with other accounts
result[:error] = e.message
end
end
results
end
end
View on GitHub (pinned to e69894adb9)
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
Defensive patterns
Strategy: try-catch
Validate before calling
# Before unlinking, confirm no concurrent sync is running against these holdings links.each do |ap| next unless ap.persisted? && ap.account.present? # skip already-removed links end Holding.where(account_provider_id: link_ids).update_all(account_provider_id: nil)
Try / catch
rescue ActiveRecord::Deadlocked, ActiveRecord::LockWaitTimeout => e
# transient contention with a running sync - safe to retry per account later
result[:error] = "lock-timeout:#{e.class}"
rescue StandardError => e
Rails.logger.warn("... failed to fully unlink provider account ##{provider_account.id} (links=#{link_ids.inspect}): #{e.class} - #{e.message}")
result[:error] = e.message
end Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- <%= class_name %>ActivitiesFetchJob - Broadcast failed: #{e.
- <%= class_name %>ConnectionCleanupJob - Failed: #{e.class} -
- <%= class_name %>ConnectionCleanupJob - API delete failed: #
- Sync failed. Please try again or contact support.
- Import::MaxRowCountExceededError
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/e40849d897bdac91.
Report an issue: GitHub.