antiwork/gumroad · error · Purchase::PurchaseInvalid
Sorry, you have not met the offer code's minimum amount.
Error message
Sorry, you have not met the offer code's minimum amount.
What it means
In Purchase::CreateService, when the applied offer code has minimum_amount_cents set, the eligible cart items' price_cents sum must reach it or Purchase::PurchaseInvalid is raised. Eligible items are all cart items minus the code's excluded_products for universal codes, or only items whose permalink is in offer_code.products otherwise — so items outside the code's scope do not count toward the minimum.
Source
Thrown at app/services/purchase/create_service.rb:107
# Check for existing subscriptions (active or restartable)
if should_check_for_restartable_subscription?
existing_purchase, error, sca_response = handle_existing_subscription
return nil, nil, sca_response if sca_response.present?
return existing_purchase, error if existing_purchase.present? || error.present?
end
end
if purchase.offer_code&.minimum_amount_cents.present?
valid_items = params[:cart_items]
valid_items = if purchase.offer_code.universal
excluded_permalinks = purchase.offer_code.excluded_products.pluck(:unique_permalink)
valid_items.reject { excluded_permalinks.include?(_1[:permalink]) }
else
valid_items.filter { purchase.offer_code.products.find_by(unique_permalink: _1[:permalink]).present? }
end
if valid_items.map { _1[:price_cents].to_i }.sum < purchase.offer_code.minimum_amount_cents
raise Purchase::PurchaseInvalid, "Sorry, you have not met the offer code's minimum amount."
end
end
if params[:accepted_offer].present?
upsell = Upsell.available_to_customers.find_by_external_id(params[:accepted_offer][:id])
raise Purchase::PurchaseInvalid, "Sorry, this offer is no longer available." unless upsell.present?
if upsell.cross_sell?
if upsell.not_replace_selected_products?
cart_product_permalinks = params[:cart_items].reject { _1[:permalink] == product.unique_permalink }.map { _1[:permalink] }
if upsell.not_is_content_upsell? && (upsell.universal ? product.user.products : upsell.selected_products).where(unique_permalink: cart_product_permalinks).empty?
raise Purchase::PurchaseInvalid, "The cart does not have any products to which the upsell applies."
end
end
# The original discount is retained if it is better than the upsell
# discount. The client can't automatically set the upsell discount
# because it doesn't have a "code". Thus, upsell discount should only
# be applied when the purchase does not already have a discount code.View on GitHub (pinned to afeacbd394)
Solutions
- Add eligible items (per the code's product scope/exclusions) until their total meets the minimum
- Use a different code without a minimum, or applicable to the products actually in the cart
- Compute the eligible-items total the same way — excluded products and non-code products do not count — before submitting payment
Defensive patterns
Strategy: validation
Validate before calling
code = purchase.offer_code
if code&.minimum_amount_cents.present?
eligible = params[:cart_items].select do |item|
code.universal ? !code.excluded_products.pluck(:unique_permalink).include?(item[:permalink]) : code.products.exists?(unique_permalink: item[:permalink])
end
raise 'below minimum' if eligible.sum { _1[:price_cents].to_i } < code.minimum_amount_cents
end Type guard
def cart_meets_offer_minimum?(cart_items, offer_code)
return true unless offer_code&.minimum_amount_cents.present?
eligible = cart_items.select do |i|
offer_code.universal ? !offer_code.excluded_products.pluck(:unique_permalink).include?(i[:permalink]) : offer_code.products.exists?(unique_permalink: i[:permalink])
end
eligible.sum { _1[:price_cents].to_i } >= offer_code.minimum_amount_cents
end Try / catch
begin
Purchase::CreateService.new(user: buyer, params: purchase_params).perform
rescue Purchase::PurchaseInvalid => e
render json: { error: e.message }, status: :unprocessable_entity # message is buyer-safe
end Prevention
- Re-validate the cart total against the code's minimum on every cart mutation, not just at apply time
- Mirror the eligibility rules: excluded products and out-of-scope products do not count toward the minimum
- Show the remaining amount needed when a code with minimum_amount_cents is applied
When it happens
Trigger: Applying a '$10 off orders over $50' code to a $30 cart; removing an item after applying the code so the eligible total drops below the minimum; a universal code whose exclusions leave zero eligible items (sum 0 < minimum).
Common situations: Buyers trim the cart at the last step; codes scoped to specific products get applied to carts containing none of them; the minimum is per eligible items only, surprising users who included excluded products.
Related errors
- Something went wrong. Please refresh the page to pre-order t
- Sorry, this offer is no longer available.
- Message is required
- That file is too large. Images can be up to #{MAX_IMAGE_BYTE
- We couldn't download that file, please check the URL and try
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/57b1cb721d027abe.
Report an issue: GitHub.