{"record":{"id":"879a6fa85262e683","repo":"antiwork/gumroad","slug":"sorry-the-price-entered-is-too-large","errorCode":null,"errorMessage":"Sorry, the price entered is too large.","messagePattern":"Sorry, the price entered is too large\\.","errorType":"exception","errorClass":"Link::LinkInvalid","httpStatus":null,"severity":"error","filePath":"app/modules/product/prices.rb","lineNumber":47,"sourceCode":"    rentable? ? prices_for_currency.select(&:is_rental?).last&.price_cents : nil\n  end\n\n  def default_price\n    return prices_for_currency.select(&:is_rental?).last if rent_only?\n\n    relevant_prices = prices_for_currency.select(&:is_buy?)\n    relevant_prices = relevant_prices.select(&:is_default_recurrence?) if is_recurring_billing && subscription_duration.present?\n    relevant_prices.last\n  end\n\n  # 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\n  # 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\n  # 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\n  # these prices are set on the variant.\n  def price_cents=(price_cents)\n    if price_cents.present? && price_cents.to_i > BasePrice::Shared::MAX_PRICE_CENTS\n      errors.add(:base, \"Sorry, the price entered is too large.\")\n      raise Link::LinkInvalid, \"Sorry, the price entered is too large.\"\n    end\n\n    return super(price_cents) if !persisted? || is_tiered_membership\n\n    create_or_update_new_price!(price_cents:, recurrence: subscription_duration.try(:to_s), is_rental: rent_only?)\n  end\n\n  def rental_price_cents=(rental_price_cents)\n    return super(rental_price_cents) unless persisted?\n\n    create_or_update_new_price!(price_cents: rental_price_cents, recurrence: subscription_duration.try(:to_s), is_rental: true)\n  end\n\n  def set_customizable_price\n    return if is_tiered_membership\n    return unless default_price_cents == 0\n    # Coffee is deliberately $0-base with paid \"Suggested Amounts\" variants and a free-entry box\n    # (initialize_suggested_amount_if_needed! sets both in one write), so the clear below would","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/modules/product/prices.rb#L29-L65","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (dollars accidentally multiplied twice)\nlink.price_cents = 1_000_000_000_00 # LinkInvalid: too large\n\n# after\nprice_cents = (dollars * 100).to_i # exactly one dollars->cents conversion\nprice_cents = nil if price_cents > BasePrice::Shared::MAX_PRICE_CENTS # reject at the boundary\nlink.price_cents = price_cents","handlingStrategy":"validation","validationCode":"MAX = BasePrice::Shared::MAX_PRICE_CENTS # 2_147_483_647\nreturn { error: 'Price too large.' } if price_cents.to_i > MAX","typeGuard":null,"tryCatchPattern":"begin\n  link.price_cents = computed_cents\nrescue Link::LinkInvalid\n  render json: { errors: link.errors.full_messages }, status: :unprocessable_entity\nend","preventionTips":["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."],"tags":["links","pricing","price-cents","int-overflow","currency","rails","linkinvalid"],"backgroundTag":"price-above-maximum","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}