{"record":{"id":"13ba11d396f599cf","repo":"antiwork/gumroad","slug":"you-have-to-confirm-your-email-address-before-you-13ba11","errorCode":null,"errorMessage":"You have to confirm your email address before you can do that.","messagePattern":"You have to confirm your email address before you can do that\\.","errorType":"exception","errorClass":"Link::LinkInvalid","httpStatus":null,"severity":"error","filePath":"app/models/link.rb","lineNumber":1664,"sourceCode":"      elsif default_offer_code.inactive?\n        errors.add(:default_offer_code, \"cannot be expired\")\n      elsif !default_offer_code.applicable?(self)\n        errors.add(:default_offer_code, \"must apply to this product\")\n      end\n    end\n\n    def enforce_not_unpublished_by_admin!\n      return unless is_unpublished_by_admin?\n\n      errors.add(:base, \"This product was unpublished by Gumroad and cannot be republished by the seller.\")\n      raise LinkInvalid, \"This product was unpublished by Gumroad and cannot be republished by the seller.\"\n    end\n\n    def enforce_user_email_confirmation!\n      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","sourceCodeStart":1646,"sourceCodeEnd":1682,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/models/link.rb#L1646-L1682","documentation":"Raised as Link::LinkInvalid by Link#enforce_user_email_confirmation! when publishing/saving a link whose user is not confirmed. Identical guard shape to the commission and installment email-confirmation guards: product publishing requires a confirmed seller identity because purchases and receipts flow from that address.","triggerScenarios":"Publishing a product (any save path running enforce_user_email_confirmation!) while link.user.confirmed? is false — new seller who never confirmed, or whose confirmation was reset.","commonSituations":"New sellers rushing to publish right after signup; test fixtures with unconfirmed users; email change flow that temporarily unsets confirmation.","solutions":["Confirm the account email (resend confirmation from settings) and retry publishing.","Gate the Publish button on user.confirmed?.","Rescue Link::LinkInvalid and render errors.full_messages."],"exampleFix":"# before\nlink.publish! # LinkInvalid: email not confirmed\n\n# after\nunless link.user.confirmed?\n  return { error: \"You have to confirm your email address before you can do that.\" }\nend\nlink.publish!","handlingStrategy":"validation","validationCode":"return { error: 'Confirm your email first.' } unless link.user.confirmed?","typeGuard":null,"tryCatchPattern":"begin\n  link.publish!\nrescue Link::LinkInvalid\n  render json: { errors: link.errors.full_messages }, status: :unprocessable_entity\nend","preventionTips":["Route unconfirmed sellers to confirmation before they reach the publish step.","The same guard exists on commissions and installments — check confirmation once at session level."],"tags":["links","publishing","email-confirmation","rails","linkinvalid","validation"],"backgroundTag":"email-not-confirmed","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}