Fix and re-import failed rows

A file with some bad rows isn't a failed import. The good rows are in, the bad ones were refunded, and every failure has a reason attached. Here's the loop for cleaning up.

Failures cost nothing

Rows that error are refunded automatically, so a file where half the rows failed only charged you for the half that worked. You can iterate as many times as you need.

Don't just re-run the whole file

Tempting, but wasteful and occasionally harmful. What happens depends on the type:

TypeRe-running the whole file
Definitions, values, metaobject entries In Skip mode the good rows skip for free and the fixed rows import. Safe, just noisier than necessary. In Update mode you'd re-write and re-pay for every good row.
Blog articles Creates duplicates — no identity, so every row becomes a new article. Never re-run an article file.

A file of only the failures is cleaner, cheaper and safe for every type.

The loop

  1. Open the job and download the failures

    Jobs → click the job → Download errors as CSV. You get import-<jobId>-errors.csv:

    import-42-errors.csv
    Row,Title,Error
    14,care_guide,"No product found matching ""merino-crewneck"""
    27,highlights,"ownerType ""PRODUCTS_VARIANT"" is not valid — did you mean ""PRODUCTVARIANT""?"
    58,loyalty_tier,"CUSTOMER metafields need the ""write_customers"" access scope, which this app hasn't been granted."
  2. Group the errors before fixing anything

    Sort by the Error column. Failures cluster — 200 rows usually share three or four causes, and each cause is one fix rather than 200. A single mis-mapped column produces the same message on every row.

  3. Find the original rows

    The Row number is 1-based and excludes the header, so error row 14 is spreadsheet row 15. Add a helper column to your source sheet numbering the data rows and you can filter directly.

  4. Fix, or accept

    Some errors are fixable in the file, some aren't. See by cause below.

  5. Build a file of just those rows

    Copy the header row from your original file, then paste the corrected rows underneath. Same columns, same order — so the mapping is identical.

  6. Run the check on the small file

    Free, and it confirms the fix worked before you spend anything. If a row is still an error, the message will have changed — that's progress.

  7. Import

    Keep the conflict mode on Skip. Rows that in fact did import the first time will skip harmlessly rather than being written twice.

Screenshot

A job with failures, and the download button

Job detail showing a non-zero Failed tile, the results table with a few error messages visible, and the “Download errors as CSV” button.

assets/screenshots/job-with-failures.png

Fixing by cause

Owner not found

error
No product found matching "merino-crewneck"

A handle, ID or SKU that doesn't exist in this store. Usually a typo, a handle that changed, or data from a different store.

Fix by re-exporting handles from Shopify (Products → Export) and matching against your file — a VLOOKUP or XLOOKUP against the real handle list finds every mismatch at once. If the product genuinely doesn't exist, create it first; ImportKit won't.

Invalid owner type

error
ownerType "PRODUCTS_VARIANT" is not valid — did you mean "PRODUCTVARIANT"?

Take the suggestion. Find and replace across the column. If it's on every row, the likelier cause is a mis-mapped column — check the mapping rather than editing the data.

Permission-blocked owner type

error
CUSTOMER metafields need the "write_customers" access scope, which this app hasn't been granted.

Not fixable. ImportKit doesn't request customer or order permissions, so those metafields are out of reach by design. Remove those rows and set those values another way. Why →

No definition and no type column

error
No metafield definition exists yet for PRODUCT custom.store_motto,
and no type column was given.

Two fixes. Better: import the definition first, then re-run these rows unchanged. Quicker: add a type column to the failures file.

Type conflict

conflict
already exists as "single_line_text_field" but this row says "multi_line_text_field"

Metafield types are immutable in Shopify. Either correct your file to match the existing type, or create a new definition under a different key. Not something any conflict mode can force.

Ambiguous SKU

error
More than one product variant has SKU "LIN-SHIRT-M" — use its ID or gid instead

Replace sku:LIN-SHIRT-M with the variant's GID. Worth also fixing the duplicate SKU in your catalogue, since it'll cause this again.

Invalid key or reserved namespace

Keys are 2–64 characters of letters, numbers, hyphens and underscores. Namespaces are 3–255 of the same, and shopify, shopify--, app-- and $app are reserved. Rename and re-run. These are caught by the pre-import check, so seeing them post-import means the check was skipped.

Something Shopify rejected

Occasionally a row passes ImportKit's validation and Shopify still says no — an unsupported capability for that metafield type, a validation rule that doesn't apply. The message is Shopify's own. Simplify the row to the minimum, import that, then add the flag back once you know which one it objected to.

Uncertain rows need a look, not a retry

A row marked uncertain was interrupted after being sent to Shopify but before its outcome was recorded. It may or may not have been created, and it wasn't charged.

Don't blindly re-import it — for a type with duplicate detection it would be caught, but for articles it would create a second copy. Check that one row in the Shopify admin, then import it only if it's missing. More →

Pending rows just need Retry

Rows still pending on a finished job were never attempted — the job was cancelled, interrupted, or ran out of credits. Those don't need a new file. Open the job and press Retry; it resumes from the first unprocessed row and never revisits rows that already succeeded. Retry and resume →

Preventing the second round

If a message doesn't make sense

Email support@importkit.app with your store domain, the job number from the URL, and the errors CSV attached. That's normally enough to answer in one reply.

Next