we-promise/sure · error · Provider::Simplefin::SimplefinError

network_error

network_error

Error message

Network error after #{max_retries} retries: #{e.message}

What it means

Raised by Provider::Simplefin.with_retries when a retryable network exception (connection reset, timeout, DNS failure, etc.) persists past MAX_RETRIES attempts. Each attempt logged a warning with the exception class and the exponential-backoff delay before sleeping and retrying; after the final failure an error is logged and SimplefinError(:network_error) wraps the last exception's message.

Source

Thrown at app/models/provider/simplefin.rb:154

      begin
        yield
      rescue *RETRYABLE_ERRORS => e
        retries += 1

        if retries <= max_retries
          delay = calculate_retry_delay(retries)
          Rails.logger.warn(
            "SimpleFin API: #{operation_name} failed (attempt #{retries}/#{max_retries}): " \
            "#{e.class}: #{e.message}. Retrying in #{delay}s..."
          )
          sleep(delay) if backoff && delay.to_f.positive?
          retry
        else
          Rails.logger.error(
            "SimpleFin API: #{operation_name} failed after #{max_retries} retries: " \
            "#{e.class}: #{e.message}"
          )
          raise SimplefinError.new(
            "Network error after #{max_retries} retries: #{e.message}",
            :network_error
          )
        end
      rescue SimplefinError => e
        # Preserve original error type and message.
        raise
      rescue => e
        # Non-retryable errors are logged and re-raised immediately
        Rails.logger.error "SimpleFin API: #{operation_name} failed with non-retryable error: #{e.class}: #{e.message}"
        raise SimplefinError.new("Exception during #{operation_name}: #{e.message}", :request_failed)
      end
    end

    # Calculate delay with exponential backoff and jitter
    def calculate_retry_delay(retry_count)
      # Exponential backoff: 2^retry * initial_delay
      base_delay = INITIAL_RETRY_DELAY * (2 ** (retry_count - 1))

View on GitHub (pinned to e69894adb9)

Solutions

  1. Confirm basic reachability from the app host: curl -v the SimpleFIN base URL - if that fails, fix local network/DNS/proxy first
  2. Re-run the operation - with exponential backoff and jitter already applied, persistent failure usually means a real connectivity problem, not a blip
  3. Check the preceding warn logs: the exception class (SocketError vs ECONNRESET vs timeout) points at DNS vs connection-drop vs slow-server
  4. If timeouts dominate, review the HTTParty timeout defaults in this class and the response size (very large accounts can exceed read timeouts)
Defensive patterns

Strategy: retry

Try / catch

begin
  simplefin.get_accounts
rescue Provider::Simplefin::SimplefinError => e
  if e.error_type == :network_error
    retry_with_backoff(max: 3) # transport failed; retry whole operation later
  else
    raise
  end
end

Prevention

When it happens

Trigger: Three consecutive network-level failures while calling the SimpleFIN access URL: Errno::ECONNRESET, Errno::ETIMEDOUT, SocketError, Net::OpenTimeout - e.g. local network down, DNS for the SimpleFIN host failing, or a firewall/middlebox dropping the connection. The HTTP request never completed, unlike server_error/fetch_failed.

Common situations: Developer machine lost connectivity mid-sync; outbound HTTPS blocked by corporate proxy; SimpleFIN host briefly unreachable; long-running Heroku/Rail dynes with flaky egress; DNS misresolution in Docker.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/c5b26f8b7b59caa2. Report an issue: GitHub.