{"record":{"id":"e5a79221baec4596","repo":"antiwork/gumroad","slug":"please-provide-suggested-payment-options","errorCode":null,"errorMessage":"Please provide suggested payment options.","messagePattern":"Please provide suggested payment options\\.","errorType":"validation","errorClass":"Link::LinkInvalid","httpStatus":null,"severity":"error","filePath":"app/services/product/variant_category_updater_service.rb","lineNumber":584,"sourceCode":"      rich_contents_to_delete.map(&:mark_deleted!)\n    end\n\n    # For tiered memberships that have per-tier pricing, validates that:\n    # 1. Any tiers that have \"pay-what-you-want\" pricing enabled have\n    # recurring price data and suggested prices are high enough\n    # 2. All tiers must have pricing info for the product's default recurrence\n    # 3. All tiers have the same set of recurrence options selected. (Currently\n    # we do not allow, e.g., Tier 1 to have monthly & yearly plans and Tier 2\n    # only to have yearly plans)\n    def validate_variant_recurrences!(variants)\n      return unless is_tiered_membership && has_variant_recurrences?\n\n      variants.each_with_index do |variant, index|\n        if variant[:customizable_price]\n          # error if \"pay what you want\" enabled but missing recurrence_price_values\n          if !variant[:recurrence_price_values].present?\n            errors.add(:base, \"Please provide suggested payment options.\")\n            raise Link::LinkInvalid, \"Please provide suggested payment options.\"\n          end\n\n          # error if \"pay what you want\" enabled but suggested price is too low\n          variant[:recurrence_price_values].each do |recurrence, price_info|\n            if price_info[:suggested_price_cents].present? && (price_info[:price_cents].to_i > price_info[:suggested_price_cents].to_i)\n              errors.add(:base, \"The suggested price you entered was too low.\")\n              raise Link::LinkInvalid, \"The suggested price you entered was too low.\"\n            end\n          end\n        end\n\n        # error if missing pricing info for the product's default recurrence\n        if product.subscription_duration.present? && (\n          !variant[:recurrence_price_values][product.subscription_duration.to_s].present? ||\n          !variant[:recurrence_price_values][product.subscription_duration.to_s][:enabled]\n        )\n          errors.add(:base, \"Please provide a price for the default payment option.\")\n          raise Link::LinkInvalid, \"Please provide a price for the default payment option.\"","sourceCodeStart":566,"sourceCodeEnd":602,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/services/product/variant_category_updater_service.rb#L566-L602","documentation":"validate_variant_recurrences! runs for tiered membership products that use variant recurrences. A tier with customizable_price (pay-what-you-want) must also supply recurrence_price_values — the suggested price for each recurrence option; a blank/missing value adds the error to :base and raises Link::LinkInvalid, aborting the save.","triggerScenarios":"Saving a tiered membership where a tier has 'pay what you want' enabled but the suggested prices (recurrence_price_values) were cleared or never filled in for its recurrence options.","commonSituations":"Toggling PWYW on an existing tier whose pricing grid was never populated; editor forms that submit the customizable_price checkbox but skip the suggestion inputs.","solutions":["Fill in a suggested price for every payment option of that tier (monthly/yearly as configured)","Or turn off 'pay what you want' for that tier so a fixed price applies","Re-save — the tier index in the error context identifies which tier is incomplete"],"exampleFix":"# before\nvariant_params = { customizable_price: true } # no recurrence_price_values\n# => Link::LinkInvalid: Please provide suggested payment options.\n\n# after\nvariant_params = {\n  customizable_price: true,\n  recurrence_price_values: {\n    'monthly' => { enabled: true, price_cents: 500, suggested_price_cents: 1500 }\n  }\n}","handlingStrategy":"validation","validationCode":"variants.each do |v|\n  next unless v[:customizable_price]\n  raise 'provide suggested payment options' if v[:recurrence_price_values].blank?\nend","typeGuard":"def tier_has_suggested_prices?(variant_params)\n  !variant_params[:customizable_price] || variant_params[:recurrence_price_values].present?\nend","tryCatchPattern":"begin\n  VariantCategoryUpdaterService.new(product:, category_params:).process\nrescue Link::LinkInvalid => e\n  render_edit_form_with(product.errors.full_messages) # message is already on :base\nend","preventionTips":["In the editor UI, disable save while a PWYW tier has no suggested price for any enabled recurrence","Treat customizable_price and recurrence_price_values as one atomic unit in payloads","The same save also enforces the default-period and same-options rules — fix all recurrence errors in one pass (252/253/254/255)"],"tags":["ruby","rails","membership","pricing","product-validation"],"backgroundTag":"missing-required-field","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}