Validation

The Hidden Dangers of Bad Data in Shopify Metaobjects (And How to Catch Them Pre-Import)

The dangerous import errors are the ones Shopify accepts. Nine checks to run before anything touches a live store, and which of them Shopify does for you.

An import that fails loudly is the good outcome. Row 87 errors, you fix it, you move on. The expensive failures are the rows Shopify accepts: a size chart linked to linen-shirt when it was meant for linen-shirt-blue, a handle someone “tidied” that created a duplicate entry, an empty cell that wiped a field on 300 entries. Nothing errors. You find out from a customer, or from a theme that suddenly renders half a table.

There’s no undo for a metaobject import. Shopify’s own help docs say a deleted entry can’t be restored, and an overwritten value is simply gone unless you saved it first. So the checking has to happen before the write. Here’s how bad data gets through, nine checks worth running before anything touches a live store, and which of those Shopify does for you.

Four ways an import goes wrong, from loudest to quietest

Loud: Shopify rejects the value

Type and validation errors: text in a number field, a value over a field’s maximum, a missing required field. Shopify refuses the write, which is what you want.

One trap for anyone scripting against the GraphQL Admin API: these errors come back as userErrors inside a normal HTTP 200 response. A rejected write looks something like this (the exact message depends on the field):

json

{
  "data": {
    "metaobjectUpsert": {
      "metaobject": null,
      "userErrors": [
        { "field": ["metaobject", "fields", "2"], "message": "Value must be an integer.", "code": "INVALID_VALUE" }
      ]
    }
  }
}

A script that only checks the status code sees 200, logs “done”, and moves on. Every write needs its userErrors read.

Partial: the run stops halfway

There’s no transaction across rows. A script that dies at row 151 leaves 150 rows written and 850 not. Shopify’s bulk mutation runner reports errors line by line and keeps going; nothing is rolled back. Either way you end up with a store that’s half old data and half new, and the only way to know which half is which is to compare against what you meant to import.

Quiet: valid but wrong

The product handle exists; it’s just the wrong product. The date is a real date; it’s just 2025 instead of 2026. No validator can catch these, because the data is valid. The only defences are comparing against the previous version and looking at the result.

Invisible: right data that doesn’t render

Everything imported correctly and customers still can’t see it:

  • Entries left in Draft on a definition that uses draft/active status.
  • A headless storefront reading a definition that isn’t exposed to the Storefront API.
  • A Liquid loop over a list of metaobjects that stops at 50 entries because it isn’t wrapped in paginate.

Nine checks to run before import

Check Example Does Shopify reject it? How to catch it first
Required field empty size_chart blank Yes, if the field is required Required-field check on every row
Wrong value format forty-two in an integer field Yes Type check per column
Breaks a field rule 60 characters where the max is 50 Yes Read the definition’s validations; check lengths and ranges
Reference doesn’t exist Product handle linen-shirt-blue A bad GID is rejected; a handle has to be resolved first Look up every handle on the target store
Duplicate handle in the file denim-jacket on rows 3 and 41 No: one write simply overwrites the other, and bulk runs don’t guarantee which Duplicate check on the handle column
Handle changed by accident slim-fit-shirt-guide-2 No: it creates a new entry Compare against existing handles; read the create count
Empty cell clears a value Blank fit_notes No Know your tool’s empty-cell rule; test on one entry
Share link instead of a file .../share/slim-fit-chart Depends on the tool Check URLs point at the file itself, with an allowed file type
Valid but wrong reference linen-shirt for linen-shirt-blue No Diff against the last export; spot-check on the storefront

Notice the pattern: the first three are caught by Shopify if nothing else catches them. The last five are never caught by Shopify. They’re accepted, written, and live.

Why validate-then-write beats write-then-fix

It’s tempting to import, look at the errors, and fix forward. That works for the loud failures. For everything else, fixing after the fact means:

  • finding the bad rows, which the import didn’t report because it didn’t consider them bad;
  • building a second import from data you may no longer have (the overwritten values);
  • recreating deleted entries, which come back with new IDs, so every product that referenced them has to be re-linked.

Checking first is cheaper in every case. A flagged row in a review screen costs a minute in the spreadsheet. The same row discovered on the storefront costs a support ticket, an investigation, and a second import.

A pre-import routine for live stores

We run this on every import to a store that’s taking orders:

  1. Export the current entries and keep the file. It’s your baseline for the diff and your backup if you need to roll back.
  2. Validate the new file and fix every flagged row. Don’t import “most of it” and promise to come back for the rest.
  3. Read the create vs update counts. If you’re editing 200 entries, you should see 200 updates and zero creates. Unexpected creates almost always mean edited or mistyped handles.
  4. Import.
  5. Read the job’s error list. Rows processed, succeeded, failed, and the reason for each failure.
  6. Check five entries on the storefront, including one you didn’t touch and one from the bottom of the file.

Steps 1 and 3 catch most of the quiet failures in the table above. Step 6 catches the invisible ones.

In Metaobjectify, steps 2 and 3 happen on the same screen: each row is marked as a create or an update, flagged rows show the reason (No product found with handle linen-shirt-blue, Required field is empty, Expected a whole number, got forty-two), and an accidental handle change shows up as a create you weren’t expecting.

The short version

  • Shopify catches type and rule violations. It doesn’t catch duplicates, changed handles, empty-cell wipes, or correct-looking wrong references.
  • Read userErrors on every write; a 200 doesn’t mean it worked.
  • Export before every import, diff before you upload, and read the create count.

For the spreadsheet side of this (diff formulas, duplicate checks, Excel’s conversion traps), see how to bulk edit metaobjects in Excel or Google Sheets. For reference checks in detail, see GIDs vs handles. And for turning step 1 into a habit, see backing up and restoring metaobjects.

Stop typing metaobjects in one at a time.

Export a definition to see the exact columns, fill it in your spreadsheet, and every row is checked before anything touches your store.