{"record":{"id":"a1b6ea154b63616f","repo":"antiwork/gumroad","slug":"giftee-purchase-errors-full-messages-0","errorCode":null,"errorMessage":"giftee_purchase.errors.full_messages[0]","messagePattern":"giftee_purchase\\.errors\\.full_messages\\[0\\]","errorType":"exception","errorClass":"Purchase::PurchaseInvalid","httpStatus":null,"severity":"error","filePath":"app/services/purchase/create_service.rb","lineNumber":508,"sourceCode":"        next if custom_field.type == CustomField::TYPE_TEXT && !custom_field.required? && values[custom_field.external_id].blank?\n        purchase.purchase_custom_fields << PurchaseCustomField.build_from_custom_field(custom_field:, value: values[custom_field.external_id], bundle_product:)\n      end\n    end\n\n    def create_giftee_purchase\n      giftee_purchase_params = purchase_params.except(:discount_code, :paypal_order_id).merge(\n        email: giftee_email,\n        is_multi_buy: false,\n        is_preorder_authorization: false,\n        perceived_price_cents: 0,\n        is_gift_sender_purchase: false,\n        is_gift_receiver_purchase: true\n      )\n      giftee_purchase = build_purchase(giftee_purchase_params)\n      giftee_purchase.purchaser = giftee_purchaser\n      giftee_purchase.gift_received = gift\n      giftee_purchase.process!\n      raise Purchase::PurchaseInvalid, giftee_purchase.errors.full_messages[0] if giftee_purchase.errors.present?\n    end\n\n    def giftee_purchaser\n      @_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\n    end\n\n    def giftee_email\n      giftee_purchaser&.email || gift_params[:giftee_email]\n    end\n\n    def build_preorder(locked_rate: nil)\n      raise Purchase::PurchaseInvalid, \"The product was just released. Refresh the page to purchase it.\" unless product.is_in_preorder_state?\n\n      self.preorder = product.preorder_link.build_preorder(purchase)\n      if purchase.is_part_of_combined_charge?\n        purchase.prepare_for_charge!(locked_rate:)\n      else\n        preorder.authorize!(locked_rate:)","sourceCodeStart":490,"sourceCodeEnd":526,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/services/purchase/create_service.rb#L490-L526","documentation":"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].","triggerScenarios":"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.","commonSituations":"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!.","solutions":["Inspect giftee_purchase.errors (all messages, not just the first) in a console or debugger to identify the failing validation.","Fix the offending field - most commonly the giftee email - and resubmit.","Integrators: log the full errors object server-side when this passthrough fires, since the raised message alone may hide additional errors."],"exampleFix":"# before: only the first error surfaces\nraise Purchase::PurchaseInvalid, giftee_purchase.errors.full_messages[0] if giftee_purchase.errors.present?\n\n# after (debugging aid): log everything, then raise the first\nRails.logger.warn(\"giftee purchase invalid: #{giftee_purchase.errors.full_messages.join(', ')}\")\nraise Purchase::PurchaseInvalid, giftee_purchase.errors.full_messages[0] if giftee_purchase.errors.present?","handlingStrategy":"try-catch","validationCode":"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\nraise ArgumentError, 'giftee user not found' if gift_params[:giftee_id].present? && giftee.nil?","typeGuard":null,"tryCatchPattern":"begin\n  purchase, error = Purchase::CreateService.new(product:, params:, buyer:).perform\nrescue Purchase::PurchaseInvalid => e\n  # passthrough of giftee_purchase model errors - log context, surface the message\n  Rails.logger.warn(\"giftee purchase invalid: #{e.message}\")\n  render_checkout_error(e.message)\nend","preventionTips":["Validate the giftee email/user exists and is alive before submitting the gift.","Log surrounding context (giftee email, purchaser email) when this fires - the raised message is only the first of possibly several errors.","Reproduce with the same giftee params in a console to see the full errors array."],"tags":["gifting","model-errors","passthrough","checkout","gumroad"],"backgroundTag":"gift-recipient-purchase-invalid","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}