{"record":{"id":"2de95ce2d128e5ab","repo":"antiwork/gumroad","slug":"your-payout-setup-hasn-t-gone-through-yet-so-you","errorCode":null,"errorMessage":"Your payout setup hasn't gone through yet, so you can't publish this product for sale. #{rejection.content}","messagePattern":"Your payout setup hasn't gone through yet, so you can't 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 the same enforce_merchant_account_exits_for_new_users! guard, but this message variant is produced when user.latest_payout_setup_rejection_note is present: Stripe rejected the seller's payout setup. The comment explains why: a rejected seller has a saved bank account and no rail, so 'connect a payment method' would point at something that already exists — the message appends the rejection note's content instead. The note lookup is keyed on the rejection's own marker, deliberately not the newest payout note (usually an unrelated skipped-payout explanation).","triggerScenarios":"Publishing while publishable? is false AND a payout-setup rejection note exists (Stripe refused the account, e.g. unsupported bank details, KYC failure, restricted country).","commonSituations":"Seller finished onboarding, saved bank details, but Stripe rejected the account; they see 'connect a payment method' and cannot understand why, since a bank account is already saved.","solutions":["Read the appended rejection.content — it is the seller-visible note recorded when Stripe refused the account and states the actual blocker.","Fix the underlying Stripe rejection (correct bank details / KYC documents) and get the account approved; publishing unblocks when can_publish_products? flips.","Contact support if the rejection looks wrong.","Rescue Link::LinkInvalid and render the full message including the rejection note."],"exampleFix":"# before: generic \"connect a payment method\" shown for rejected sellers (misleading)\n# after: surface the rejection reason, as publish_blocked_message does\nmessage = if (rejection = user.latest_payout_setup_rejection_note)\n  \"Your payout setup hasn't gone through yet, so you can't publish this product for sale. #{rejection.content}\"\nelse\n  \"You must connect at least one payment method before you can publish this product for sale.\"\nend","handlingStrategy":"validation","validationCode":"if (rejection = user.latest_payout_setup_rejection_note)\n  return { blocked: true, reason: rejection.content } # surface the Stripe rejection reason\nend","typeGuard":null,"tryCatchPattern":"begin\n  link.publish!\nrescue Link::LinkInvalid\n  render json: { errors: link.errors.full_messages }, status: :unprocessable_entity # includes the rejection note content\nend","preventionTips":["A saved bank account does not mean a working rail — check latest_payout_setup_rejection_note before telling sellers to 'connect a payment method'.","Show the rejection note's content verbatim; it names the actual Stripe refusal.","Publish unblocks only when can_publish_products? turns true after the account is approved."],"tags":["links","publishing","payouts","stripe","account-rejected","rails","linkinvalid"],"backgroundTag":"payout-setup-rejected","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}