antiwork/gumroad · error · Purchase::PurchaseInvalid
Tip is too large for this purchase
Error message
Tip is too large for this purchase
What it means
Raised when the tip would push the payment below the product's floor: perceived_price_cents.ceil minus tip_cents.floor is less than purchase.minimum_paid_price_cents. On pay-what-you-want products minimum_paid_price_cents is the seller's minimum price, so the amount entered must cover both the product minimum and the tip.
Source
Thrown at app/services/purchase/create_service.rb:146
purchase.offer_code = upsell.offer_code
end
end
purchase.build_upsell_purchase(
upsell:,
selected_product: Link.find_by_external_id(params[:accepted_offer][:original_product_id]),
upsell_variant: params[:accepted_offer][:original_variant_id].present? ?
upsell.upsell_variants.alive.find_by(
selected_variant: BaseVariant.find_by_external_id(params[:accepted_offer][:original_variant_id])
) :
nil
)
raise Purchase::PurchaseInvalid, purchase.upsell_purchase.errors.first.message unless purchase.upsell_purchase.valid?
end
if params[:tip_cents].present? && params[:tip_cents] > 0
raise Purchase::PurchaseInvalid, "Tip is not allowed for this product" unless purchase.seller.tipping_enabled? && product.not_is_tiered_membership?
raise Purchase::PurchaseInvalid, "Tip is too large for this purchase" if (purchase_params[:perceived_price_cents].ceil - params[:tip_cents].floor) < purchase.minimum_paid_price_cents
purchase.build_tip(value_cents: params[:tip_cents], value_usd_cents: get_usd_cents(product.price_currency_type, params[:tip_cents]))
end
validate_bundle_products
purchase.prepare_for_charge!(locked_rate: buyer_currency_quote_rate_hint(purchase))
purchase.build_purchase_wallet_type(wallet_type: params[:wallet_type]) if params[:wallet_type].present?
payment_flow_attributes = PurchasePaymentFlow.attributes_for_checkout_params(params)
# The purchase may still be unsaved here: `prepare_for_charge!` leaves it
# unpersisted when a validation fails (for example, an invalid email).
# Creating the dependent analytics row on an unsaved parent raises
# ActiveRecord::RecordNotSaved, and a purchase that never saved has no
# payment flow worth recording anyway.
if payment_flow_attributes && purchase.persisted? && !purchase.free_purchase?
beginView on GitHub (pinned to afeacbd394)
Solutions
- Lower the tip so that price minus tip stays at or above the product minimum.
- Increase the total amount entered so it absorbs both the minimum and the tip.
- Integrators: enforce tip_cents <= perceived_price_cents - minimum_paid_price_cents before enabling submit.
Example fix
# before: tip accepted without bound (total 500c, minimum 100c, tip 450c -> 50 < 100) params[:tip_cents] = 450 # after: clamp the tip to what the entered price can cover max_tip = purchase_params[:perceived_price_cents].ceil - minimum_paid_price_cents params[:tip_cents] = [params[:tip_cents].to_i, max_tip].min
Defensive patterns
Strategy: validation
Validate before calling
tip = params[:tip_cents].to_i.floor price = purchase_params[:perceived_price_cents].to_i.ceil params[:tip_cents] = 0 if tip > 0 && (price - tip) < minimum_paid_price_cents
Type guard
def tip_within_bounds?(perceived_price_cents, tip_cents, minimum_paid_price_cents) (perceived_price_cents.to_i.ceil - tip_cents.to_i.floor) >= minimum_paid_price_cents end
Try / catch
begin Purchase::CreateService.new(product:, params:, buyer:).perform rescue Purchase::PurchaseInvalid => e # ask the buyer to lower the tip or raise the entered amount; do not auto-retry render_checkout_error(e.message) if e.message == 'Tip is too large for this purchase' end
Prevention
- Cap the tip input at perceived price minus the product minimum in the UI.
- Compute every amount in integer cents; never send dollars.
- Remember the server rounds the price up (.ceil) and the tip down (.floor) - leave a small buffer for rounding.
When it happens
Trigger: Any submission where (purchase_params[:perceived_price_cents].ceil - params[:tip_cents].floor) < purchase.minimum_paid_price_cents - e.g. a PWYW product with a $1 minimum, buyer enters $1.00 total and adds a $0.50 tip: 100 - 50 = 50 < 100.
Common situations: Pay-what-you-want checkouts with generous tips; clients computing perceived_price_cents in dollars instead of cents; rounding drift between client and server (the server rounds the price up and the tip down).
Related errors
- Tip is not allowed for this product
- Purchase price is invalid. Please check the price.
- The cart does not have any products to which the upsell appl
- You can't gift your own product. To give it away for free, c
- You cannot gift a product to yourself. Please try gifting to
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/9b8e6fad7f9cb90f.
Report an issue: GitHub.