spree/spree · error · Spree::Core::GatewayError

gateway_error

gateway_error

Error message

Unable to connect to gateway.

What it means

Raised by Spree::Refund#process! when the refund request never reaches a gateway response: the underlying payment call raises Spree::PaymentConnectionError (timeout, DNS failure, refused connection) and it is rescued and re-raised as Spree::Core::GatewayError with the translated 'unable_to_connect_to_gateway' text. It is distinct from a declined refund, which surfaces the gateway's own decline message instead. It means the state of the refund at the provider is unknown, not that the refund failed.

Source

Thrown at spree/core/app/models/spree/refund.rb:154

        if payment.payment_method.payment_profiles_supported?
          payment.payment_method.credit(refund_total_in_cents, payment.source, payment.transaction_id, originator: self)
        else
          payment.payment_method.credit(refund_total_in_cents, payment.transaction_id, originator: self)
        end
      end

      if response.success?
        track_order_as_refunded(refund_total_in_cents)
      else
        Rails.logger.error(Spree.t(:gateway_error) + "  #{response.to_yaml}")
        text = response.params['message'] || response.params['response_reason_text'] || response.message
        raise Core::GatewayError, text
      end

      response
    rescue Spree::PaymentConnectionError => e
      Rails.logger.error(Spree.t(:gateway_error) + "  #{e.inspect}")
      raise Core::GatewayError, Spree.t(:unable_to_connect_to_gateway)
    end

    def calculate_refund_amount(credit_cents)
      # Overwrite this for more complex calculations
      credit_cents
    end

    def track_order_as_refunded(credit_cents)
      # You can track refunds here
    end

    def amount_is_less_than_or_equal_to_allowed_amount
      if amount > payment.credit_allowed
        errors.add(:amount, :greater_than_allowed)
      end
    end

    # Re-sums the order this refund put right. Read through the refund's own

View on GitHub (pinned to 06bf66a868)

Solutions

  1. Verify network egress from the app host to the payment provider API (curl the provider's API hostname) and fix firewall/proxy/VPN issues.
  2. Check the payment method's configuration (mode, API endpoint, credentials) in the Admin API and correct any wrong values.
  3. Before retrying, check the provider's dashboard (or API) for whether the refund actually landed despite the connection error — a timed-out request may still have been processed.
  4. Retry the refund once connectivity is confirmed; if the provider is unreachable for an extended period, refund in the provider console and record it, or queue the refund for a background retry job.

Example fix

# before
refund.process!(amount_in_cents)

# after — handle connection loss distinctly from a decline
begin
  refund.process!(amount_in_cents)
rescue Spree::Core::GatewayError => e
  if e.message == Spree.t(:unable_to_connect_to_gateway)
    Rails.logger.warn("Refund #{refund.number} not confirmed at gateway: #{e.message}")
    RefundRetryJob.perform_later(refund.id, amount_in_cents) # verifies state at gateway before retrying
  else
    raise # real decline: surface it
  end
end
Defensive patterns

Strategy: retry

Try / catch

begin
  refund.process!(amount_in_cents)
rescue Spree::Core::GatewayError => e
  if e.message == Spree.t(:unable_to_connect_to_gateway)
    # outcome unknown: check the refund at the provider BEFORE retrying,
    # then retry once from a background job — never blind-loop
    RefundVerificationJob.perform_later(refund.id)
  else
    raise # decline or other gateway error: surface, do not retry
  end
end

Prevention

When it happens

Trigger: Calling refund.process! / creating a refund through Payments::Refund while the app host cannot open a connection to the payment provider's API: network outage, egress firewall blocking the provider hostname, wrong API endpoint configured on the payment method, or the provider itself being down.

Common situations: Local development without internet access, staging servers behind restrictive proxies, a typo in the gateway URL preference, provider-side incidents, VPN dropping mid-request, or test suites accidentally hitting live gateway endpoints.

Related errors


AI-assisted analysis of spree/spree@06bf66a868 (2026-08-21). Data as JSON: /api/errors/03d0bc449501b78e. Report an issue: GitHub.