{"record":{"id":"53e45d33618673c2","repo":"we-promise/sure","slug":"sync-failed-please-try-again-or-contact-support-53e45d","errorCode":null,"errorMessage":"Sync failed. Please try again or contact support.","messagePattern":"Sync failed\\. Please try again or contact support\\.","errorType":"exception","errorClass":"WiseItem::Syncer::SafeSyncError","httpStatus":null,"severity":"error","filePath":"app/models/wise_item/syncer.rb","lineNumber":71,"sourceCode":"      )\n      sync_errors.concat(result_failure_errors(schedule_results, category: :account_sync_error, message_key: :account_sync_failed))\n\n      # Phase 5: Collect transaction statistics\n      account_ids = wise_item.wise_accounts\n                             .joins(:account_provider)\n                             .includes(account_provider: :account)\n                             .filter_map { |wa| wa.current_account&.id }\n      collect_transaction_stats(sync, account_ids: account_ids, source: \"wise\")\n    end\n\n    collect_health_stats(sync, errors: sync_errors.presence)\n  rescue => e\n    safe_message = user_safe_error_message(e)\n    Rails.logger.error \"WiseItem::Syncer - sync failed for item #{wise_item.id}: #{e.class} - #{e.message}\"\n    Rails.logger.error Array(e.backtrace).first(10).join(\"\\n\")\n    Sentry.capture_exception(e) { |s| s.set_tags(wise_item_id: wise_item.id) }\n    collect_health_stats(sync, errors: [ { message: safe_message, category: \"sync_error\" } ])\n    raise SafeSyncError, safe_message\n  end\n\n  def perform_post_sync\n    # no-op\n  end\n\n  private\n\n    def update_status(sync, key, **options)\n      return unless sync.respond_to?(:status_text)\n\n      sync.update!(status_text: I18n.t(\"wise_items.syncer.#{key}\", **options))\n    end\n\n    def collect_wise_setup_stats(sync, total_count:, linked_count:, unlinked_count:)\n      return unless sync.respond_to?(:sync_stats)\n\n      merge_sync_stats(sync, {","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/wise_item/syncer.rb#L53-L89","documentation":"Raised as SafeSyncError by WiseItem::Syncer (app/models/wise_item/syncer.rb:71) after ANY exception escapes the Wise sync body. The syncer logs the original class/message and backtrace, reports it to Sentry tagged with wise_item_id, records a health-stats entry (category sync_error) using a user-safe i18n message — 'credentials_invalid' for Provider::Wise::WiseError with error_type unauthorized/access_forbidden, otherwise the generic 'Sync failed. Please try again or contact support.' — and then re-raises that sanitized message. The original error is intentionally hidden from users.","triggerScenarios":"Any failure inside perform_sync: Wise API 5xx/timeout, expired or revoked API tokens (WiseError unauthorized), malformed payloads, or a bug in the import pipeline. The SafeSyncError you catch is a wrapper; the real cause is only in logs/Sentry.","commonSituations":"Expired Wise API token triggering the unauthorized path; transient Wise outage surfacing as the generic message; users retrying sync repeatedly without effect because the underlying cause (e.g. revoked token) persists.","solutions":["Look up the real cause in Sentry (tag wise_item_id) or the Rails log lines 'WiseItem::Syncer - sync failed for item <id>' — the SafeSyncError text alone is deliberately uninformative.","If the user-facing message is the credentials-invalid variant, re-authorize/re-enter the Wise API token on the item and sync again.","For transient network/API failures, retry the sync once after a short delay.","If cause is unclear, reproduce with the item's credentials via Provider::Wise directly to separate auth problems from data problems."],"exampleFix":"// before\nbegin\n  WiseItem::Syncer.new(item).perform_sync(sync)\nrescue => e\n  retry # loops on the same persistent failure\nend\n\n// after\nbegin\n  WiseItem::Syncer.new(item).perform_sync(sync)\nrescue SafeSyncError => e\n  Rails.logger.warn(\"wise sync failed safely: #{e.message}\") # real cause is in Sentry\nend","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  WiseItem::Syncer.new(item).perform_sync(sync)\nrescue SafeSyncError => e\n  # e.message is sanitized/user-safe; real cause is in Sentry (tag wise_item_id)\n  retry if transient?(e.message) # only for known-transient messages\nend","preventionTips":["Never parse the SafeSyncError message to infer cause — correlate via Sentry wise_item_id tag or the Rails log lines instead.","Alert on the credentials_invalid variant specifically: it needs user re-auth, not a retry.","Bound retries; a persistent underlying failure will keep re-raising the same safe message."],"tags":["rails","wise","sync","error-wrapping","sentry"],"backgroundTag":"sync-failure-wrapped","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}