{"record":{"id":"e62fbd579d9b879b","repo":"we-promise/sure","slug":"could-not-sync-akahu-connection","errorCode":null,"errorMessage":"Could not sync Akahu connection","messagePattern":"Could not sync Akahu connection","errorType":"exception","errorClass":"AkahuItem::Syncer::SafeSyncError","httpStatus":null,"severity":"warning","filePath":"app/models/akahu_item/syncer.rb","lineNumber":67,"sourceCode":"        window_end_date: sync.window_end_date\n      )\n      raise_if_failed_results!(schedule_results, stage: \"Akahu account sync scheduling\")\n\n      account_ids = linked_accounts.includes(:account_provider).filter_map { |aa| aa.current_account&.id }\n      collect_transaction_stats(sync, account_ids: account_ids, source: \"akahu\")\n    else\n      Rails.logger.info \"AkahuItem::Syncer - No linked accounts to process\"\n    end\n\n    collect_health_stats(sync, errors: nil)\n  rescue SyncError => e\n    collect_health_stats(sync, errors: e.sync_errors)\n    raise\n  rescue => e\n    safe_message = I18n.t(\"akahu_item.errors.sync_failed\")\n    Rails.logger.error \"AkahuItem::Syncer - Unexpected sync error: #{e.class}\"\n    collect_health_stats(sync, errors: [ { message: safe_message, category: \"sync_error\" } ])\n    raise SafeSyncError.new(safe_message), cause: nil\n  end\n\n  def perform_post_sync\n    # no-op\n  end\n\n  private\n\n    def raise_if_failed_result!(result, stage:)\n      return unless failed_result?(result)\n\n      errors = errors_from_result(result, stage: stage)\n      raise SyncError.new(error_message(stage, errors), sync_errors: errors)\n    end\n\n    def raise_if_failed_results!(results, stage:)\n      errors = Array(results).filter_map do |result|\n        next unless failed_result?(result)","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/akahu_item/syncer.rb#L49-L85","documentation":"Raised by validate_date_range! when end_date exceeds start_date + 5.years. It is a hard client-side cap on the query window for the securities screening endpoint, enforced before any request. Yahoo's screener rejects oversized windows, so the provider fails fast instead of making a doomed call. Split large windows into multiple ≤5-year chunks to fetch the full history.","triggerScenarios":"Passing decade-long ranges (e.g., 2010-01-01..2025-01-01) to the search/screening API; building a 'since inception' chart from first-trade date to today; defaulting start_date to a fixed epoch like 2000-01-01.","commonSituations":"Long-history backfills after a user changes their 'history start' setting; porting code from another provider with no window cap; tests using wide fixtures.","solutions":["Chunk the request into consecutive ≤5-year windows and merge results","Clamp start_date to end_date - 5.years when only recent data matters","Compute the minimum number of windows needed (ceil of days/5y) in the caller","Surface the cap in UI date pickers so users cannot request oversized ranges"],"exampleFix":"# before\nprovider.search_securities(query: q, start_date: Date.new(2000, 1, 1), end_date: Date.today)\n\n# after\nwindows = []\ncursor = Date.new(2000, 1, 1)\nwhile cursor < Date.today\n  windows << [cursor, [cursor + 5.years - 1.day, Date.today].min]\n  cursor += 5.years\nend\nresults = windows.flat_map { |s, e| provider.search_securities(query: q, start_date: s, end_date: e) }","handlingStrategy":"validation","validationCode":"MAX_WINDOW = 5.years - 1.day\nraise ArgumentError, \"range too large\" if end_date.to_date - start_date.to_date > MAX_WINDOW","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Chunk any multi-year backfill into consecutive ≤5-year windows","Clamp 'since inception' requests to end_date - 5.years when full history isn't required","Cap date pickers in the UI to the provider's window"],"tags":["yahoo-finance","date-validation","range-limit","pagination"],"backgroundTag":"date-range-limit-exceeded","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}