{"record":{"id":"647c6b196905eeae","repo":"we-promise/sure","slug":"lunchflow-provider-is-not-configured","errorCode":null,"errorMessage":"Lunchflow provider is not configured","messagePattern":"Lunchflow provider is not configured","errorType":"exception","errorClass":"StandardError","httpStatus":null,"severity":"error","filePath":"app/models/lunchflow_item.rb","lineNumber":38,"sourceCode":"\n  has_many :lunchflow_accounts, dependent: :destroy\n  has_many :accounts, through: :lunchflow_accounts\n\n  scope :active, -> { where(scheduled_for_deletion: false) }\n  scope :syncable, -> { active }\n  scope :ordered, -> { order(created_at: :desc) }\n  scope :needs_update, -> { where(status: :requires_update) }\n\n  def destroy_later\n    update!(scheduled_for_deletion: true)\n    DestroyJob.perform_later(self)\n  end\n\n  def import_latest_lunchflow_data\n    provider = lunchflow_provider\n    unless provider\n      Rails.logger.error \"LunchflowItem #{id} - Cannot import: Lunchflow provider is not configured (missing API key)\"\n      raise StandardError.new(\"Lunchflow provider is not configured\")\n    end\n\n    LunchflowItem::Importer.new(self, lunchflow_provider: provider).import\n  rescue => e\n    Rails.logger.error \"LunchflowItem #{id} - Failed to import data: #{e.message}\"\n    raise\n  end\n\n  def process_accounts\n    return [] if lunchflow_accounts.empty?\n\n    results = []\n    # Only process accounts that are linked and have active status\n    lunchflow_accounts.joins(:account).merge(Account.visible).each do |lunchflow_account|\n      begin\n        result = LunchflowAccount::Processor.new(lunchflow_account).process\n        results << { lunchflow_account_id: lunchflow_account.id, success: true, result: result }\n      rescue => e","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/lunchflow_item.rb#L20-L56","documentation":"AuthenticationError raised when the cookie/crumb bootstrap raises a generic Faraday::Error (connection failure, TLS error, timeout, DNS) before any crumb is obtained — the rescue converts the transport error into an auth error with the Faraday message appended. The 429 case is handled separately as RateLimitError, so this specifically means the bootstrap HTTP requests themselves failed, not that Yahoo rejected credentials.","triggerScenarios":"fetch_cookie_and_crumb hitting network failure to fc.yahoo.com or query1.finance.yahoo.com (DNS refusal, TLS handshake failure, connection reset); proxy/firewall blocking Yahoo; IPv6 misrouting on the host; Faraday adapter misconfiguration raising a non-429 Faraday::Error.","commonSituations":"Server with no outbound internet or strict egress firewall; captive DNS in CI containers; expired CA bundle breaking TLS to Yahoo; flaky home/office uplink during nightly syncs.","solutions":["Check outbound connectivity: curl -I https://fc.yahoo.com from the same host","Fix DNS/proxy/firewall rules to allow fc.yahoo.com and query1.finance.yahoo.com","Update CA certificates / Faraday TLS config if the handshake fails","Retry with backoff for transient resets; this rescue has no built-in retry","Verify the Faraday connection object in Provider::YahooFinance is configured with a working adapter"],"exampleFix":"# before\nprovider.fetch_security_prices(symbol: s, start_date: a, end_date: b)\n# raises AuthenticationError: Failed to authenticate with Yahoo Finance: connection refused\n\n# after (caller-side retry for transient transport failures)\nbegin\n  provider.fetch_security_prices(symbol: s, start_date: a, end_date: b)\nrescue Provider::YahooFinance::AuthenticationError => e\n  raise unless /timeout|reset|refused|could not resolve/i.match?(e.message)\n  sleep 30\n  retry if (tries += 1) < 3\n  raise\nend","handlingStrategy":"retry","validationCode":"require \"net/http\"\nuri = URI(\"https://fc.yahoo.com\")\nNet::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.head(\"/\") } # fail fast if egress blocked","typeGuard":null,"tryCatchPattern":"tries = 0\nbegin\n  provider.fetch_security_prices(symbol: s, start_date: a, end_date: b)\nrescue Provider::YahooFinance::AuthenticationError => e\n  transient = /timeout|reset|refused|could not resolve|ssl/i.match?(e.message)\n  raise unless transient && (tries += 1) < 3\n  sleep(30)\n  retry\nend","preventionTips":["Verify outbound access to fc.yahoo.com and query1.finance.yahoo.com in deployment checks","Keep CA certificates and the Faraday adapter stack current","Don't treat transport-failure auth errors as credential problems — check the appended Faraday message"],"tags":["yahoo-finance","authentication","faraday","network","tls","dns"],"backgroundTag":"api-authentication-failed","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}