“Validation failed: options are not unique”

Validation failed: options are not unique

This one really does stop the import, which makes it the most expensive error on the list and the most useful to catch early. The cause is almost never the variant you are looking at.

Check your file in the converterRuns in this browser. Nothing is uploaded, and the check happens before you download.

Why Shopify raises it

Inside one product, a variant is identified by its combination of option values. Two variants with the same combination are the same variant twice, and Shopify refuses the file rather than guess which you meant.

Shopify’s solutions to common product CSV import problems gives both causes under this exact message: “This error is caused when a product has duplicate options. You might have set up a product with two variants with the same option values (for example, 2 medium products, both in black). If the option values are unique, then a product could be duplicated elsewhere in the CSV with the same handle.”

The second sentence is the one that costs people an afternoon: the duplicate may be nowhere near the row the error names, because it is another block of rows claiming the same handle further down the file. Shopify also warns that reported line numbers “might not match with row numbers in your CSV”, since a quoted description containing newlines shifts the count.

How to find it in your CSV

Build a key per row from the handle plus the three option values, concatenated, and look for duplicates in that key — not in any single column. Blank counts as a value: two rows with no option values at all are a duplicate combination, which is why an empty variant row is the commonest trigger of this error.

Three shapes produce almost all cases. A parent row copied through as a variant: WooCommerce and Magento both export a parent row carrying the title and the list of allowed values, and if it becomes a variant row its option cells are blank or hold “Small, Medium, Large”. A declared option with a missing value: once a product sets Option2 name: Colour, every variant row needs a colour, and two rows missing it collide with each other. And two products sharing a handle, as the help page describes.

How the converter prevents it

Three rules in src/lib/validate.ts, matching the three shapes above.

options_not_unique groups rows by handle, builds the option-value combination for each, and reports every row in any combination claimed more than once:

Duplicate variant “M / Charcoal” inside product “waxed-canvas-cap”. Shopify fails the import with “options are not unique”.

A combination of all-blanks is shown as (no option values) rather than as an empty string, so the empty-variant case reads as a real finding instead of a blank message.

option_value_missing catches the second shape before it becomes the first: for each option name a product declares, every variant row must have a value in that slot, and a gap is reported as Option “Colour” has no value on this variant.

handle_duplicate catches the third: two separate product rows under one handle are reported with their row numbers, which is the case Shopify’s help page describes as a product “duplicated elsewhere in the CSV”.

Upstream of all three, the converter avoids creating the problem in the first place. When it detects a parent-placeholder row — several rows grouped together where the first row’s option cells are empty or comma-separated lists while later rows hold single values — it uses that row for product-level fields only and does not emit it as a variant. That is the WooCommerce and Magento shape, handled structurally rather than reported.

What a correct fix looks like

If the two rows are genuinely different things, give them different option values — that is what options are for. If one of them is a parent placeholder, it should not be a variant row at all: its title, description and images belong on the product’s first row and its option cells should be empty.

If you have run out of option axes — you need a fourth dimension and Shopify allows three — the answer is not to overload a value. Shopify’s adding-variants page is explicit that three options is the hard limit and points to third-party apps or line-item properties for a fourth. Splitting into two products is usually the simpler answer.

Before you retry the import

  • Fix the file, not the symptom. Shopify reports the first failure it meets, so a second error usually appears once the first is cleared.
  • Import into a development store or a draft-status batch first, so a half-correct file cannot put wrong data in front of customers.
  • If you are overwriting existing products by handle, export your live products first: a blank cell in the import can erase a value that is currently there.

Column-by-column reference: the Shopify product CSV format. Nexum Gate is not affiliated with Shopify Inc.