antiwork/gumroad · error · Purchase::PurchaseInvalid

giftee_purchase.errors.full_messages[0]

Error message

giftee_purchase.errors.full_messages[0]

What it means

Gift checkouts build a second, recipient-side purchase (perceived_price_cents forced to 0, is_gift_receiver_purchase true) and run process! on it. If that giftee purchase ends up with validation errors, the first full message is re-raised as PurchaseInvalid - so the message text is whatever the underlying model validation produced, not a fixed string. This is a passthrough of giftee_purchase.errors.full_messages[0].

Source

Thrown at app/services/purchase/create_service.rb:508

        next if custom_field.type == CustomField::TYPE_TEXT && !custom_field.required? && values[custom_field.external_id].blank?
        purchase.purchase_custom_fields << PurchaseCustomField.build_from_custom_field(custom_field:, value: values[custom_field.external_id], bundle_product:)
      end
    end

    def create_giftee_purchase
      giftee_purchase_params = purchase_params.except(:discount_code, :paypal_order_id).merge(
        email: giftee_email,
        is_multi_buy: false,
        is_preorder_authorization: false,
        perceived_price_cents: 0,
        is_gift_sender_purchase: false,
        is_gift_receiver_purchase: true
      )
      giftee_purchase = build_purchase(giftee_purchase_params)
      giftee_purchase.purchaser = giftee_purchaser
      giftee_purchase.gift_received = gift
      giftee_purchase.process!
      raise Purchase::PurchaseInvalid, giftee_purchase.errors.full_messages[0] if giftee_purchase.errors.present?
    end

    def giftee_purchaser
      @_giftee_purchaser ||= gift_params[:giftee_id].present? ? User.alive.find_by_external_id(gift_params[:giftee_id]) : User.alive.by_email(gift_params[:giftee_email]).last
    end

    def giftee_email
      giftee_purchaser&.email || gift_params[:giftee_email]
    end

    def build_preorder(locked_rate: nil)
      raise Purchase::PurchaseInvalid, "The product was just released. Refresh the page to purchase it." unless product.is_in_preorder_state?

      self.preorder = product.preorder_link.build_preorder(purchase)
      if purchase.is_part_of_combined_charge?
        purchase.prepare_for_charge!(locked_rate:)
      else
        preorder.authorize!(locked_rate:)

View on GitHub (pinned to afeacbd394)

Solutions

  1. Inspect giftee_purchase.errors (all messages, not just the first) in a console or debugger to identify the failing validation.
  2. Fix the offending field - most commonly the giftee email - and resubmit.
  3. Integrators: log the full errors object server-side when this passthrough fires, since the raised message alone may hide additional errors.

Example fix

# before: only the first error surfaces
raise Purchase::PurchaseInvalid, giftee_purchase.errors.full_messages[0] if giftee_purchase.errors.present?

# after (debugging aid): log everything, then raise the first
Rails.logger.warn("giftee purchase invalid: #{giftee_purchase.errors.full_messages.join(', ')}")
raise Purchase::PurchaseInvalid, giftee_purchase.errors.full_messages[0] if giftee_purchase.errors.present?
Defensive patterns

Strategy: try-catch

Validate before calling

giftee = gift_params[:giftee_id].present? ? User.alive.find_by_external_id(gift_params[:giftee_id]) : User.alive.by_email(gift_params[:giftee_email]).last
raise ArgumentError, 'giftee user not found' if gift_params[:giftee_id].present? && giftee.nil?

Try / catch

begin
  purchase, error = Purchase::CreateService.new(product:, params:, buyer:).perform
rescue Purchase::PurchaseInvalid => e
  # passthrough of giftee_purchase model errors - log context, surface the message
  Rails.logger.warn("giftee purchase invalid: #{e.message}")
  render_checkout_error(e.message)
end

Prevention

When it happens

Trigger: Gift flow completes create_gift, giftee_purchase.process! runs, and giftee_purchase.errors is non-empty afterwards - e.g. recipient-side email or purchase-model validations failing on the zero-priced receiver purchase.

Common situations: Giftee email that fails user/purchase validations; giftee account state issues (deleted/alive checks in giftee_purchaser lookup); any recipient-side model validation tripping during process!.

Related errors


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