antiwork/gumroad · error · Link::LinkInvalid

The suggested price you entered was too low.

Error message

The suggested price you entered was too low.

What it means

For a pay-what-you-want tier, each recurrence's entry is checked: if suggested_price_cents is present and price_cents (the tier's price for that recurrence) is greater than it, the suggestion sits below the tier's own price, so the save fails with Link::LinkInvalid. The suggested amount must be at least the tier price for that recurrence.

Solutions

  1. Raise the suggested price to at least the tier's price for that recurrence
  2. Or lower the tier's price (price_cents) to or below the suggested price
  3. Double-check both fields are in cents and belong to the same recurrence (monthly vs yearly mix-ups are common)

Example fix

# before
{ price_cents: 1000, suggested_price_cents: 500 } # $10 tier, $5 suggestion
# => Link::LinkInvalid: The suggested price you entered was too low.

# after
{ price_cents: 1000, suggested_price_cents: 1500 } # $10 tier, $15 suggestion
Defensive patterns

Strategy: validation

Validate before calling

variant_params[:recurrence_price_values].each do |recurrence, info|
  next unless info[:suggested_price_cents].present?
  if info[:price_cents].to_i > info[:suggested_price_cents].to_i
    raise "suggested price for #{recurrence} is below the tier price"
  end
end

Try / catch

begin
  VariantCategoryUpdaterService.new(product:, category_params:).process
rescue Link::LinkInvalid
  render_edit_form_with(product.errors.full_messages)
end

Prevention

When it happens

Trigger: A tier priced at $10/month whose suggested price for 'monthly' is set to $5 — price_cents (1000) > suggested_price_cents (500) trips the raise.

Common situations: Editors entering the suggestion in the wrong field or the wrong unit (dollars vs cents), or lowering a tier's base price assumption after suggestions were already set.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/2e0521e8f003f155. Report an issue: GitHub.

Appendix: source

Thrown at app/services/product/variant_category_updater_service.rb:591

    # 3. All tiers have the same set of recurrence options selected. (Currently
    # we do not allow, e.g., Tier 1 to have monthly & yearly plans and Tier 2
    # only to have yearly plans)
    def validate_variant_recurrences!(variants)
      return unless is_tiered_membership && has_variant_recurrences?

      variants.each_with_index do |variant, index|
        if variant[:customizable_price]
          # error if "pay what you want" enabled but missing recurrence_price_values
          if !variant[:recurrence_price_values].present?
            errors.add(:base, "Please provide suggested payment options.")
            raise Link::LinkInvalid, "Please provide suggested payment options."
          end

          # error if "pay what you want" enabled but suggested price is too low
          variant[:recurrence_price_values].each do |recurrence, price_info|
            if price_info[:suggested_price_cents].present? && (price_info[:price_cents].to_i > price_info[:suggested_price_cents].to_i)
              errors.add(:base, "The suggested price you entered was too low.")
              raise Link::LinkInvalid, "The suggested price you entered was too low."
            end
          end
        end

        # error if missing pricing info for the product's default recurrence
        if product.subscription_duration.present? && (
          !variant[:recurrence_price_values][product.subscription_duration.to_s].present? ||
          !variant[:recurrence_price_values][product.subscription_duration.to_s][:enabled]
        )
          errors.add(:base, "Please provide a price for the default payment option.")
          raise Link::LinkInvalid, "Please provide a price for the default payment option."
        end
      end

      # error if variants have different recurrence options:
      # 1. Extract variant recurrence selections:
      # Ex. [["monthly", "yearly"], ["monthly"]]
      enabled_recurrences_for_variants = variants.map do |variant|

View on GitHub (pinned to afeacbd394)