antiwork/gumroad · error · Link::LinkInvalid

Memberships should only have one Tier version category.

Error message

Memberships should only have one Tier version category.

What it means

Raised as Link::LinkInvalid by Link#valid_tier_version_structure when a membership product does not have exactly one alive variant_category. Memberships are modeled with a single 'Tier' variant category holding the tier variants; 0 or 2+ alive categories breaks that contract and the save is aborted. Skipped entirely for deleted or archived links, or when purchase_disabled_at just changed.

Source

Thrown at app/models/link.rb:1884

    def alive_category_variants_presence
      return if deleted_at.present?
      return if archived?

      has_alive_categories_without_variants = variant_categories.alive.left_joins(:alive_variants).where(base_variants: { id: nil }).exists?

      if has_alive_categories_without_variants
        errors.add(:base, "Sorry, the product versions must have at least one option.")
      end
    end

    def valid_tier_version_structure
      return if deleted_at.present?
      return if archived?
      return if purchase_disabled_at.present? && purchase_disabled_at_changed?

      if variant_categories.alive.size != 1
        errors.add(:base, "Memberships should only have one Tier version category.")
        raise LinkInvalid, "Memberships should only have one Tier version category."
        return
      end

      if variant_categories.alive.first.variants.alive.size == 0
        errors.add(:base, "Memberships should have at least one tier.")
        raise LinkInvalid, "Memberships should have at least one tier."
      end
    end

    def quantity_enabled_state_is_allowed
      if quantity_enabled && !can_enable_quantity?
        errors.add(:base, "Customers cannot be allowed to choose a quantity for this product.")
      end
    end

    def custom_permalink_or_is_licensed_changed?
      custom_permalink_changed? || is_licensed_changed?
    end

View on GitHub (pinned to afeacbd394)

Solutions

  1. Ensure membership products have exactly one alive variant category named for tiers; soft-delete extras before saving.
  2. For API-created memberships, create the single Tier category then its variants — never multiple categories.
  3. Rescue Link::LinkInvalid and show errors.full_messages.

Example fix

# before: two alive categories on a membership
link.variant_categories.alive.count # => 2
link.save! # LinkInvalid

# after: keep exactly one Tier category
link.variant_categories.alive.where.not(name: "Tier").each(&:mark_deleted)
link.save!
Defensive patterns

Strategy: validation

Validate before calling

return { error: 'One Tier category required.' } if link.is_membership && link.variant_categories.alive.size != 1

Try / catch

begin
  link.save!
rescue Link::LinkInvalid
  render json: { errors: link.errors.full_messages }, status: :unprocessable_entity
end

Prevention

When it happens

Trigger: Saving an alive, non-archived membership link whose variant_categories.alive count is not 1 — creating a membership with no Tier category, or a duplicate Tier category (often via API/imports creating categories directly).

Common situations: Bulk importers or API clients creating variant categories the UI never would; cleanup scripts that soft-delete the one alive category; migrations leaving stray alive categories on membership links.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/9effbbe81cf58acd. Report an issue: GitHub.