antiwork/gumroad · error · Link::LinkInvalid
Cannot update variant rich content while the product uses sh
Error message
Cannot update variant rich content while the product uses shared content for all variants. Update product-level rich content instead, or set has_same_rich_content_for_all_variants to false first.
What it means
Link::LinkInvalid raised in Api::V2::VariantsController#update inside the transaction, after @product.lock!, when the request includes rich_content but the product still has has_same_rich_content_for_all_variants true. In shared mode variant-level content is not authoritative — writes must go to the product-level endpoint, or the flag must be flipped false first, otherwise the variant content would be shadowed by the shared set.
Source
Thrown at app/controllers/api/v2/variants_controller.rb:37
else
error_with_creating_object(:variant, variant)
end
end
def show
success_with_variant(@variant)
end
def update
ActiveRecord::Base.transaction do
if !@variant.update(permitted_params)
raise ActiveRecord::Rollback
end
if params.key?(:rich_content)
@product.lock!
if @product.has_same_rich_content_for_all_variants?
raise Link::LinkInvalid, "Cannot update variant rich content while the product uses shared content for all variants. Update product-level rich content instead, or set has_same_rich_content_for_all_variants to false first."
end
save_variant_rich_content!(@variant)
file_ids = @variant.alive_rich_contents.flat_map { _1.embedded_product_file_ids_in_order }.uniq
if file_ids.any?
scoped_files = @product.product_files.alive.where(id: file_ids).to_a
if scoped_files.length != file_ids.length
missing = file_ids - scoped_files.map(&:id)
missing_external = missing.map { ObfuscateIds.encrypt(_1) }
raise Link::LinkInvalid, "File embeds reference files not belonging to this product: #{missing_external.join(", ")}"
end
@variant.product_files = scoped_files
else
@variant.product_files = []
end
Product::SavePostPurchaseCustomFieldsService.new(@product).performView on GitHub (pinned to afeacbd394)
Solutions
- Update product-level rich content instead (links endpoint) — in shared mode that is the single source the variants render.
- Or send has_same_rich_content_for_all_variants: false on the product first, then write variant content (mind the migrate_to_per_variant constraints).
- In clients, branch on the product's flag before choosing the variant vs product endpoint.
- Refetch the product if the mode may have changed since your last read — the guard re-checks under lock.
Example fix
# before: variant rich_content on a shared-content product VariantApi.update(link_id, variant_id, rich_content: pages) # -> LinkInvalid # after: flip the product to per-variant mode first LinkApi.update(link_id, has_same_rich_content_for_all_variants: false) VariantApi.update(link_id, variant_id, rich_content: pages)
Defensive patterns
Strategy: validation
Validate before calling
product = LinkApi.get(link_id) raise ModeError if params.key?(:rich_content) && product.has_same_rich_content_for_all_variants?
Type guard
def variant_rich_content_writable?(product) !product.has_same_rich_content_for_all_variants? || product.alive_variants.empty? end
Prevention
- Check the product's shared-content flag before calling the variant rich-content endpoint.
- Flip the flag on the product first when per-variant content is intended.
- Refetch product state at request time in multi-client setups.
When it happens
Trigger: PUT/PATCH /api/v2/links/:link_id/variants/:id (or nested equivalent) with a rich_content key while the parent product uses shared content for all variants; the guard fires before save_variant_rich_content! so nothing is written.
Common situations: Integrations that always write per-variant content regardless of product mode; UI per-variant editor reachable on a shared-content product; state changed by another client between page load and submit.
Related errors
- Cannot update product-level rich content while in per-varian
- Cannot switch to shared content: both product-level and vari
- Cannot switch to shared content: multiple variants have dist
- Cannot switch to per-variant content: the product has no var
- File embeds reference files not belonging to this product: #
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/70e78f44a0bde19b.
Report an issue: GitHub.