antiwork/gumroad · error · Purchase::PurchaseInvalid
Sorry, this offer is no longer available.
Error message
Sorry, this offer is no longer available.
What it means
When params[:accepted_offer] is present, Purchase::CreateService looks the upsell up in Upsell.available_to_customers.find_by_external_id(params[:accepted_offer][:id]). If no available upsell matches (not found, no longer available_to_customers, expired, or deleted by the seller), Purchase::PurchaseInvalid is raised and the purchase does not proceed with the offer.
Source
Thrown at app/services/purchase/create_service.rb:113
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.
if purchase.offer_code.blank? && upsell.offer_code&.evaluate_for_buyer(buyer, product: purchase.link).present? &&
(!params[:is_purchasing_power_parity_discounted] || perceived_price_matches_accepted_offer?(upsell.offer_code))
purchase.offer_code = upsell.offer_code
end
end
purchase.build_upsell_purchase(View on GitHub (pinned to afeacbd394)
Solutions
- Refresh the checkout page — if the offer is still live it will be re-offered with a valid reference
- Otherwise complete the purchase without the upsell; the base purchase is unaffected
- If building a client, treat accepted_offer as optional and re-validate availability before submitting
Defensive patterns
Strategy: fallback
Validate before calling
if params[:accepted_offer].present? upsell = Upsell.available_to_customers.find_by_external_id(params[:accepted_offer][:id]) raise 'offer no longer available' if upsell.nil? end
Type guard
def accepted_offer_still_available?(offer_id) Upsell.available_to_customers.exists?(external_id: offer_id) end
Try / catch
begin
Purchase::CreateService.new(user: buyer, params: purchase_params).perform
rescue Purchase::PurchaseInvalid => e
if e.message.include?('no longer available')
purchase_params.delete(:accepted_offer) # complete the base purchase without the upsell
retry
else
raise
end
end Prevention
- Treat accepted_offer as advisory: re-check Upsell.available_to_customers right before submit
- Expect offers to expire between render and accept — always keep a purchase-without-offer path
- Short-lived checkout sessions for products with time-limited upsells reduce the window for this race
When it happens
Trigger: Accepting an upsell that expired or was deleted between when the checkout page rendered and when the buyer clicked accept; a stale checkout tab; a wrong or tampered accepted_offer id in the request.
Common situations: Time-limited upsell offers; sellers editing/deleting upsells while carts are open; long-lived checkout pages on mobile.
Related errors
- Something went wrong. Please refresh the page to pre-order t
- Sorry, you have not met the offer code's minimum amount.
- 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/e97b01f942f140da.
Report an issue: GitHub.