antiwork/gumroad · error · Link::LinkInvalid
Cannot update product-level rich content while in per-varian
Error message
Cannot update product-level rich content while in per-variant mode. Set has_same_rich_content_for_all_variants to true first, or use the variant endpoint to update per-variant content.
What it means
Link::LinkInvalid raised in Api::V2::LinksController#update when the request includes rich_content (product-level) but the product is in per-variant content mode (has_same_rich_content_for_all_variants is false) and alive variants exist. Product-level content and per-variant content are mutually exclusive states; the API refuses to write product-level pages that no variant would render, and tells you to flip the flag first or use the per-variant endpoint.
Source
Thrown at app/controllers/api/v2/links_controller.rb:506
end
validate_file_embed_conflicts!(skip_variant_embeds: flag_changed && @product.has_same_rich_content_for_all_variants? && !@normalized_rich_content.nil?)
rich_content_params = build_rich_content_params
file_id_mappings = SaveFilesService.perform(@product, { files: @normalized_files }, rich_content_params) || {}
end
@product.save!
@product.save_tags!(params[:tags]) if params.key?(:tags)
if params.key?(:cover_ids)
cover_ids = normalize_params_recursively(params[:cover_ids])
@product.reorder_previews(cover_ids.map.with_index.to_h)
end
if !@normalized_rich_content.nil? && !@product.has_same_rich_content_for_all_variants? && @product.alive_variants.exists?
raise Link::LinkInvalid, "Cannot update product-level rich content while in per-variant mode. Set has_same_rich_content_for_all_variants to true first, or use the variant endpoint to update per-variant content."
end
if flag_changed
if @normalized_rich_content.nil?
migrate_rich_content_for_flag_change!
else
clear_inactive_rich_content_side!
strip_upsell_ids_from_normalized_rich_content!
end
end
rich_content_or_flag_changed = !@normalized_rich_content.nil? || flag_changed
unless @normalized_rich_content.nil?
save_rich_content!
end
if rich_content_or_flag_changedView on GitHub (pinned to afeacbd394)
Solutions
- If you want one shared content set: send has_same_rich_content_for_all_variants: true in the same (or a prior) request, then the rich_content write is accepted (see migrate_to_shared_rich_content! constraints).
- If variants should keep distinct content: write to the variant endpoint (Api::V2::VarientsController-style per-variant rich_content update) instead of product-level.
- In shared clients, GET the product first and branch on has_same_rich_content_for_all_variants before choosing which endpoint to call.
- Don't ignore the flag and force product-level writes — you would clobber the per-variant content model.
Example fix
# before: product-level rich_content on a per-variant product LinkApi.update(link_id, rich_content: pages) # after: flip to shared mode in the same payload LinkApi.update(link_id, has_same_rich_content_for_all_variants: true, rich_content: pages)
Defensive patterns
Strategy: validation
Validate before calling
product = LinkApi.get(link_id) if product.has_same_rich_content_for_all_variants LinkApi.update(link_id, rich_content: pages) else VariantApi.update(link_id, variant_id, rich_content: pages) end
Type guard
def product_level_rich_content_writable?(product) product.has_same_rich_content_for_all_variants? || product.alive_variants.empty? end
Prevention
- Branch on has_same_rich_content_for_all_variants before choosing the endpoint.
- Flip the flag and the content in one request when switching modes.
- Refetch the product before writes in long-lived editor sessions.
When it happens
Trigger: PATCH /api/v2/links/:id with a rich_content key while the product has variants and has_same_rich_content_for_all_variants is false (previously switched to per-variant mode); the guard runs after the primary save, so it rejects the content-shape mismatch on the request boundary.
Common situations: Integration assumes every product takes product-level rich_content, but the seller had switched the product to per-variant; a template apply-script hitting variant-mode products; migration scripts that set rich_content before flipping the shared flag.
Related errors
- 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
- Cannot update variant rich content while the product uses sh
- File embeds reference files not belonging to this product: #
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/aa70b5b608eda47a.
Report an issue: GitHub.