antiwork/gumroad · error · Purchase::PurchaseInvalid

Purchase price is invalid. Please check the price.

Error message

Purchase price is invalid. Please check the price.

What it means

validate_perceived_price raises when perceived_price_cents falls outside Purchase::MAX_PRICE_RANGE (-2_147_483_647..2_147_483_647, the signed 32-bit integer bounds of the price column, app/models/purchase.rb:51). Values beyond that cannot be stored, so checkout aborts before the purchase is built.

Source

Thrown at app/services/purchase/create_service.rb:347

      raise Purchase::PurchaseInvalid, "You can't gift your own product. To give it away for free, create a 100% off discount code under Checkout > Discounts and share the checkout link." if buyer == product.user
      raise Purchase::PurchaseInvalid, "You cannot gift a product to yourself. Please try gifting to another email." if giftee_email == purchase_params[:email]
      raise Purchase::PurchaseInvalid, "Gift purchases cannot be on installment plans." if params[:pay_in_installments]

      if product.can_gift?
        gift = product.gifts.build(giftee_email:, gift_note: gift_params[:gift_note], gifter_email: params[:purchase][:email], is_recipient_hidden: gift_params[:giftee_email].blank?)
        error_message = gift.save ? nil : gift.errors.full_messages[0]
        raise Purchase::PurchaseInvalid, error_message if error_message.present?

        gift
      else
        error_message = product.user.gifting_disabled? ? "The creator has disabled gifting for their products." : "Gifting is not yet enabled for pre-orders."
        raise Purchase::PurchaseInvalid, error_message
      end
    end

    def validate_perceived_price
      if purchase_params[:perceived_price_cents] && !Purchase::MAX_PRICE_RANGE.cover?(purchase_params[:perceived_price_cents])
        raise Purchase::PurchaseInvalid, "Purchase price is invalid. Please check the price."
      end
    end

    def validate_zip_code
      country_code_for_validation = purchase_params[:country].presence || purchase_params[:sales_tax_country_code_election]

      if purchase_params[:perceived_price_cents].to_i > 0 && country_code_for_validation == Compliance::Countries::USA.alpha2 && UsZipCodes.identify_state_code(purchase_params[:zip_code]).nil?
        Rails.logger.info("Zip code #{purchase_params[:zip_code]} is invalid, customer email #{purchase_params[:email]}")
        raise Purchase::PurchaseInvalid, "You entered a ZIP Code that doesn't exist within your country."
      end
    end

    def perceived_price_matches_accepted_offer?(offer_code)
      return false unless offer_code

      original_offer_code = purchase.offer_code
      purchase.offer_code = offer_code
      purchase.minimum_paid_price_cents + params[:tip_cents].to_i == purchase_params[:perceived_price_cents].to_i

View on GitHub (pinned to afeacbd394)

Solutions

  1. Send integer cents, converted from the decimal amount exactly once.
  2. Validate or clamp the client input to the int32 range before submit.
  3. If a legitimate charge truly exceeds the range, it exceeds what Gumroad can price - split it or contact support.

Example fix

# before: cents conversion applied twice
params[:purchase][:perceived_price_cents] = (price_dollars * 100 * 100).to_i

# after: convert to integer cents exactly once
params[:purchase][:perceived_price_cents] = (price_dollars * 100).to_i
Defensive patterns

Strategy: validation

Validate before calling

price_cents = purchase_params[:perceived_price_cents].to_i
raise ArgumentError, 'perceived_price_cents out of range' unless Purchase::MAX_PRICE_RANGE.cover?(price_cents)

Type guard

def valid_price_cents?(cents)
  cents.is_a?(Numeric) && Purchase::MAX_PRICE_RANGE.cover?(cents.to_i)
end

Try / catch

begin
  Purchase::CreateService.new(product:, params:, buyer:).perform
rescue Purchase::PurchaseInvalid => e
  # a range violation is a client bug - log it and reject, do not retry the same value
  report_client_bug(e.message) if e.message == 'Purchase price is invalid. Please check the price.'
end

Prevention

When it happens

Trigger: params[:purchase][:perceived_price_cents] is non-nil and outside the int32 range - typically dollars converted to cents twice, float multiplication overflow, or a tampered request probing the bounds.

Common situations: Client multiplies a dollar amount by 100 twice; price parsed as dollars in one layer and cents in another; PWYW inputs accepted without an upper bound; automated requests submitting extreme values.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/c7e601777a461037. Report an issue: GitHub.