antiwork/gumroad · error · Link::LinkInvalid
Sorry, the price entered is too large.
Error message
Sorry, the price entered is too large.
What it means
Raised as Link::LinkInvalid by the price_cents= setter in Product::Prices (app/modules/product/prices.rb:44) when the assigned value exceeds BasePrice::Shared::MAX_PRICE_CENTS, which is 2_147_483_647 (app/modules/base_price/shared.rb:57) — the signed 32-bit integer ceiling, since price cents are stored as an int column. The guard fires inside the setter, before any Price record creation, and also mirrors in Price validations.
Solutions
- Fix the cents computation at the source — ensure the value passed is truly minor units (amount * 100 applied exactly once).
- Validate client-side against the ceiling: reject or cap at BasePrice::Shared::MAX_PRICE_CENTS (2147483647) before assigning; note links_controller already clamps to this range.
- For weak-currency products, check the product currency's max-price rules rather than blindly converting USD-equivalents.
- Rescue Link::LinkInvalid and show errors.full_messages.
Example fix
# before (dollars accidentally multiplied twice) link.price_cents = 1_000_000_000_00 # LinkInvalid: too large # after price_cents = (dollars * 100).to_i # exactly one dollars->cents conversion price_cents = nil if price_cents > BasePrice::Shared::MAX_PRICE_CENTS # reject at the boundary link.price_cents = price_cents
Defensive patterns
Strategy: validation
Validate before calling
MAX = BasePrice::Shared::MAX_PRICE_CENTS # 2_147_483_647
return { error: 'Price too large.' } if price_cents.to_i > MAX Try / catch
begin
link.price_cents = computed_cents
rescue Link::LinkInvalid
render json: { errors: link.errors.full_messages }, status: :unprocessable_entity
end Prevention
- Apply the dollars→cents conversion (×100) exactly once, at one boundary.
- Validate against 2_147_483_647 (int32) client-side; controllers already clamp to this range.
- For weak-currency markets (IDR/VND), check the currency's own max-price rules instead of converting USD equivalents.
When it happens
Trigger: Assigning link.price_cents (directly or via link params / API) with an integer above 2_147_483_647 — commonly a currency-conversion bug passing whole-currency units where cents are expected (e.g. $2,148,484 entered as 2148484 * 100), or low-denomination currencies (IDR, VND) converting to astronomical cent values.
Common situations: Client computing cents wrong (dollars passed as cents); price feeds/imports for weak-currency markets; admin tooling multiplying by 100 twice; tests asserting with values beyond int32.
Related errors
- Memberships should have at least one tier.
- Memberships should only have one Tier version category.
- Sorry, shipping destinations have to be unique.
- The product needs to be shippable to at least one…
- This product was unpublished by Gumroad and cannot be…
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/879a6fa85262e683.
Report an issue: GitHub.
Appendix: source
Thrown at app/modules/product/prices.rb:47
rentable? ? prices_for_currency.select(&:is_rental?).last&.price_cents : nil
end
def default_price
return prices_for_currency.select(&:is_rental?).last if rent_only?
relevant_prices = prices_for_currency.select(&:is_buy?)
relevant_prices = relevant_prices.select(&:is_default_recurrence?) if is_recurring_billing && subscription_duration.present?
relevant_prices.last
end
# Public: Sets the buy price of the product to price_cents. If the product is already persisted then it changes the Price(s) associated with the
# product to achieve that. If the product hasn't been persisted yet it simply sets the price_cents attribute and relies on associate_price to
# create and associated the proper Price(s) object. If the product is a tiered membership product, it does not create or update a new price since
# these prices are set on the variant.
def price_cents=(price_cents)
if price_cents.present? && price_cents.to_i > BasePrice::Shared::MAX_PRICE_CENTS
errors.add(:base, "Sorry, the price entered is too large.")
raise Link::LinkInvalid, "Sorry, the price entered is too large."
end
return super(price_cents) if !persisted? || is_tiered_membership
create_or_update_new_price!(price_cents:, recurrence: subscription_duration.try(:to_s), is_rental: rent_only?)
end
def rental_price_cents=(rental_price_cents)
return super(rental_price_cents) unless persisted?
create_or_update_new_price!(price_cents: rental_price_cents, recurrence: subscription_duration.try(:to_s), is_rental: true)
end
def set_customizable_price
return if is_tiered_membership
return unless default_price_cents == 0
# Coffee is deliberately $0-base with paid "Suggested Amounts" variants and a free-entry box
# (initialize_suggested_amount_if_needed! sets both in one write), so the clear below wouldView on GitHub (pinned to afeacbd394)