antiwork/gumroad · error · Link::LinkInvalid
Your payout setup hasn't gone through yet, so you can't publ
Error message
Your payout setup hasn't gone through yet, so you can't publish this product for sale. #{rejection.content} What it means
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).
Source
Thrown at app/models/link.rb:1679
return if user.confirmed?
errors.add(:base, "You have to confirm your email address before you can do that.")
raise LinkInvalid, "You have to confirm your email address before you can do that."
end
def enforce_shipping_destinations_presence!
return unless is_physical
return if shipping_destinations.alive.present?
errors.add(:base, "The product needs to be shippable to at least one destination.")
raise LinkInvalid, "The product needs to be shippable to at least one destination."
end
def enforce_merchant_account_exits_for_new_users!
return if publishable?
errors.add(:base, publish_blocked_message)
raise LinkInvalid, publish_blocked_message
end
# A seller whose payout setup Stripe rejected has a saved bank account and no rail, so telling
# them to connect a payment method sends them looking for something that is already there. Point
# at the rejection instead — the seller-visible note recorded when Stripe refused the account
# (gumroad-private#1777).
#
# Keyed on the note's own marker rather than on the newest seller-visible payout note, which is
# usually an unrelated skipped-payout explanation.
def publish_blocked_message
rejection = user.latest_payout_setup_rejection_note
return "You must connect at least one payment method before you can publish this product for sale." if rejection.blank?
"Your payout setup hasn't gone through yet, so you can't publish this product for sale. #{rejection.content}"
end
def free_trial_only_enabled_if_recurring_billing
if !is_recurring_billing && (free_trial_enabled? || free_trial_duration_unit.present? || free_trial_duration_amount.present?)View on GitHub (pinned to afeacbd394)
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.
Example fix
# before: generic "connect a payment method" shown for rejected sellers (misleading)
# after: surface the rejection reason, as publish_blocked_message does
message = if (rejection = user.latest_payout_setup_rejection_note)
"Your payout setup hasn't gone through yet, so you can't publish this product for sale. #{rejection.content}"
else
"You must connect at least one payment method before you can publish this product for sale."
end Defensive patterns
Strategy: validation
Validate before calling
if (rejection = user.latest_payout_setup_rejection_note)
return { blocked: true, reason: rejection.content } # surface the Stripe rejection reason
end Try / catch
begin
link.publish!
rescue Link::LinkInvalid
render json: { errors: link.errors.full_messages }, status: :unprocessable_entity # includes the rejection note content
end Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- You must connect at least one payment method before you can
- This product was unpublished by Gumroad and cannot be republ
- You have to confirm your email address before you can do tha
- Sorry, shipping destinations have to be unique.
- The product needs to be shippable to at least one destinatio
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/2de95ce2d128e5ab.
Report an issue: GitHub.