antiwork/gumroad · error
Sorry, something went wrong. Please try again.
Error message
Sorry, something went wrong. Please try again.
What it means
Purchase::CreateService serializes checkouts of products that don't allow parallel purchases with a Redis-backed inventory semaphore (acquisition timeout 50 seconds, INVENTORY_LOCK_ACQUISITION_TIMEOUT). If semaphore.lock returns nil — the per-product lock stayed held for the entire window — perform returns [nil, "Sorry, something went wrong. Please try again."] after a warn log naming the product id. Nothing was charged; this is pure lock contention, not a payment failure.
Source
Thrown at app/services/purchase/create_service.rb:27
attr_reader :product, :params, :purchase_params, :gift_params, :buyer
attr_accessor :purchase, :gift
def initialize(product:, params:, buyer: nil)
@product = product
@params = params
@purchase_params = params[:purchase]
@gift_params = params[:gift].presence
@buyer = buyer
@force_new_subscription = !!params[:force_new_subscription]
end
def perform
unless @product.allow_parallel_purchases?
inventory_semaphore = inventory_lock_client
inventory_lock_token = inventory_semaphore.lock
if inventory_lock_token.nil?
Rails.logger.warn("Could not acquire lock for product_inventory semaphore (product id: #{@product.id})")
return nil, "Sorry, something went wrong. Please try again."
end
end
begin
# create gift if necessary
self.gift = create_gift if is_gift?
# run pre-build validations
validate_perceived_price
validate_zip_code
# build primary (non-gift) purchase
self.purchase = build_purchase(purchase_params.merge(gift_given: gift))
purchase.submitted_pre_discount_price_cents = params[:submitted_pre_discount_price_cents]
purchase.once_per_cart_discount_allocation = params[:once_per_cart_discount_allocation]
if purchase.once_per_cart_discount_allocation.present?
purchase.offer_code = OfferCode.find_by(id: purchase.once_per_cart_discount_allocation[:offer_code_id])
endView on GitHub (pinned to afeacbd394)
Solutions
- Retry the purchase — the lock releases when the in-flight checkout finishes and the next attempt acquires it.
- If it persists, check Redis health and whether the semaphore for the product id in the warn log has leaked (holder crashed without release).
- Debounce or disable the buy button client-side to cut duplicate concurrent attempts.
Defensive patterns
Strategy: retry
Validate before calling
# Cheap pre-check: fail fast (or queue) when contention is likely locked = inventory_lock_client.lock unless @product.allow_parallel_purchases? return retry_later if locked.nil? # instead of burning the full 50s window
Try / catch
# perform returns a tuple, not an exception purchase, error = Purchase::CreateService.new(product:, params:, buyer:).perform if error == "Sorry, something went wrong. Please try again." && purchase.nil? retry_with_backoff # lock contention is transient; nothing was charged end
Prevention
- Disable the buy button after the first click to cut duplicate lock holders.
- Keep the post-lock critical section short so concurrent buyers queue briefly instead of timing out.
- Monitor the "Could not acquire lock for product_inventory semaphore" warn log for leaked semaphores and Redis degradation.
When it happens
Trigger: Two or more concurrent checkouts of a limited-inventory product where an earlier holder keeps the lock for the full 50s (slow charge under load), a previous holder crashed so the lock waits out its TTL, Redis unavailable or slow, or a flash-sale burst exceeding what the semaphore admits.
Common situations: Product drops and flash sales on limited products; buyer double-clicks; retry storms after a partial outage; elevated charge-processor latency stretching each holder's critical section.
Related errors
- This email is already being sent. Please wait a few minutes
- Please wait a few seconds and try sending again.
- responseData.error_message
- json.message
- Something went wrong.
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/f6291c70c31cb9bb.
Report an issue: GitHub.