{"record":{"id":"96d49c17793aecde","repo":"antiwork/gumroad","slug":"you-must-connect-at-least-one-payment-method-befor","errorCode":null,"errorMessage":"You must connect at least one payment method before you can publish this product for sale.","messagePattern":"You must connect at least one payment method before you can publish this product for sale\\.","errorType":"exception","errorClass":"Link::LinkInvalid","httpStatus":null,"severity":"error","filePath":"app/models/link.rb","lineNumber":1679,"sourceCode":"      return if user.confirmed?\n\n      errors.add(:base, \"You have to confirm your email address before you can do that.\")\n      raise LinkInvalid, \"You have to confirm your email address before you can do that.\"\n    end\n\n    def enforce_shipping_destinations_presence!\n      return unless is_physical\n      return if shipping_destinations.alive.present?\n\n      errors.add(:base, \"The product needs to be shippable to at least one destination.\")\n      raise LinkInvalid, \"The product needs to be shippable to at least one destination.\"\n    end\n\n    def enforce_merchant_account_exits_for_new_users!\n      return if publishable?\n\n      errors.add(:base, publish_blocked_message)\n      raise LinkInvalid, publish_blocked_message\n    end\n\n    # A seller whose payout setup Stripe rejected has a saved bank account and no rail, so telling\n    # them to connect a payment method sends them looking for something that is already there. Point\n    # at the rejection instead — the seller-visible note recorded when Stripe refused the account\n    # (gumroad-private#1777).\n    #\n    # Keyed on the note's own marker rather than on the newest seller-visible payout note, which is\n    # usually an unrelated skipped-payout explanation.\n    def publish_blocked_message\n      rejection = user.latest_payout_setup_rejection_note\n      return \"You must connect at least one payment method before you can publish this product for sale.\" if rejection.blank?\n\n      \"Your payout setup hasn't gone through yet, so you can't publish this product for sale. #{rejection.content}\"\n    end\n\n    def free_trial_only_enabled_if_recurring_billing\n      if !is_recurring_billing && (free_trial_enabled? || free_trial_duration_unit.present? || free_trial_duration_amount.present?)","sourceCodeStart":1661,"sourceCodeEnd":1697,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/models/link.rb#L1661-L1697","documentation":"Raised as Link::LinkInvalid by Link#enforce_merchant_account_exits_for_new_users! when publishing while publishable? (delegates to user.can_publish_products?, app/models/link.rb:602) is false and no payout-setup rejection note exists. The message comes from publish_blocked_message, which returns this generic variant when user.latest_payout_setup_rejection_note is blank — i.e. the seller simply has no connected payout rail yet.","triggerScenarios":"Publishing a product as a seller who has not connected any payment/payout method (no merchant account usable for charges), with no recorded Stripe payout-setup rejection.","commonSituations":"New sellers skipping the payouts onboarding step and going straight to publishing; disconnected/removed all payout accounts; sandbox accounts without connected Stripe.","solutions":["Complete payout setup (connect a payment method / Stripe account) in settings, confirm user.can_publish_products? becomes true, then publish.","Gate the Publish action on user.can_publish_products? so sellers are routed to payouts onboarding first.","Rescue Link::LinkInvalid and show errors.full_messages."],"exampleFix":"# before\nlink.publish! # LinkInvalid: must connect a payment method\n\n# after\nunless link.user.can_publish_products?\n  return { error: \"You must connect at least one payment method before you can publish this product for sale.\" }\nend\nlink.publish!","handlingStrategy":"validation","validationCode":"return { error: 'Connect a payment method first.' } unless link.user.can_publish_products?","typeGuard":null,"tryCatchPattern":"begin\n  link.publish!\nrescue Link::LinkInvalid\n  render json: { errors: link.errors.full_messages }, status: :unprocessable_entity\nend","preventionTips":["Gate publishing on user.can_publish_products? (what publishable? delegates to).","Send sellers through payouts onboarding before the product form.","After connecting a method, verify the flag flips before retrying publish."],"tags":["links","publishing","payouts","stripe","onboarding","rails","linkinvalid"],"backgroundTag":"payment-account-not-connected","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}