Skip to Content
TroubleshootingCommon errors

Common errors

What follows is a triage table for the errors that actually come up in production. If you see something not listed, contact the Graftport team with the run item link and the error text — we’ll add it here.

Source connectivity

Error / symptomLikely causeWhat to do
401 Unauthorized on extractWrong credentials, or admin password rotated.Update the credential in the migration’s settings. Re-run extract.
403 Forbidden on a specific resourceThe admin user is missing read scope for that resource.Grant the scope on the source platform; no need to re-issue the credential.
429 Too Many Requests repeatedlySource platform’s rate limit hit.Graftport backs off automatically. If it persists for hours, ask the source platform to raise your limit.
Extract hangs at 0 rowsSource API reachable but returning empty pages, often a misconfigured store domain.Verify the domain in credentials matches what you can browse to. No protocol, no slash.
An orders extract from a Shopify source is refused, naming read_all_ordersThe custom app on the source store can only see the last 60 days of orders. Shopify doesn’t report that as an error — it just stops — so Graftport refuses to start rather than migrate a two-month slice of the order history.Tick read_all_orders on the custom app’s Admin API scopes, reinstall the app, update the access token in the migration if it changed, and re-run. See Shopify as source.
Far fewer orders extracted than the store has, and the run says it succeededA run from before this check existed, on a store whose app lacked read_all_orders — the count stops at exactly 60 days of orders.Grant read_all_orders as above, then re-run extract. The re-extract picks up the full history.

Uploaded files

Error / symptomLikely causeWhat to do
”Couldn’t read any JSON objects from this file.”The file isn’t JSON Lines — one JSON object per line — or its first records are something else (an array, a bare value, plain text).Re-export as JSON Lines. A single JSON array in one line-wrapped block is a different format and won’t read.
”Couldn’t find a header row in this file.”The CSV’s first row isn’t column names, or the file is empty.Re-export with a header row.
The picker sits on “Reading file…” for a whileNormal for a very large export — Graftport counts its rows before uploading.Wait for the column and row counts to appear; a ~1 GB file takes a few seconds.
”The object exceeded the maximum allowed size”The file is over the 1 GB upload limit.Split the export into several files and add each as its own source, or export a narrower date range.
A run says the file “ends mid-record” and “looks truncated”The export was cut off before it finished writing — the last record is incomplete.Re-export the file. If you can’t, delete its final incomplete line and upload again. Re-uploading over the existing source keeps the mapping you’ve already written.

Mapping / transform

Error / symptomLikely causeWhat to do
JSONata error: instance member of …Mapping references a field that doesn’t exist on this row.Use field ? field : default in the mapping, or filter out rows where the field is missing.
JSONata error: cannot evaluate functionCalling a non-existent function (typo, missing $ prefix).Fix the function name; save creates a new version.
Output is null for some rows but the source row looks fineThe mapping returns nothing when an early condition fails.Use the editor’s sample input with that source row to step through.
Transform produces unexpected payload but JSONata “looks right”Pinned mapping version is older than what’s in the editor.Check the migration’s mapping → version pin. Re-pin and re-transform.
INVALID_FORMAT on phoneThe source phone can’t be read as a real number, and Shopify only accepts E.164 (+15555550123).Map country next to phone — a local number from any country is converted for you once the country is known. If it still fails, the number is the wrong length for that country, or the value is junk rather than a number: blank it in the mapping.
A product loads with the warning stock … is negative … so it was set to 0The source store oversold that line and carries stock below zero. Shopify can’t hold a negative on-hand quantity, so Graftport loads the product with 0 in stock rather than failing the whole record and losing its title, price and images too.Nothing to fix if 0 is the right answer. To land a different number, correct the stock in the source and re-run, or set the quantity in the mapping (for example, clamping to a minimum of 1 for back-orderable lines).
INVALID_FORMAT on quantityThe mapping’s stock field isn’t a number — usually it’s pointed at the wrong source column.Check what the field returns in the mapping editor’s sample input, and point it at the numeric stock column.

Destination / Shopify load

Error / symptomLikely causeWhat to do
Access denied for write_…Token’s scopes are missing the resource.Reissue token with the correct scopes; update destination credential.
RECONNECT_STORE, and the run, purge or redirect job stops part-wayThe destination store’s connection can no longer be renewed — the app was uninstalled or reinstalled on that store, access was revoked, or the connection sat unused past its 90-day life. Graftport stops immediately rather than failing every remaining record one at a time.Reconnect the store from Stores, then run again. Records that already loaded are left alone; the run picks up where it stopped.
SHOPIFY_BUNDLES_NOT_ENABLEDThe destination store doesn’t have the Shopify Bundles app installed; bundle records can’t load without it.Install the Shopify Bundles app  on the destination store and re-run.
MISSING_REFERENCE on a bundleA bundle product loaded before the products it bundles together; those component products weren’t on the destination yet.Re-run the load — components load first, so a second pass resolves the bundle. If it persists, the component products are out of scope; include them in the run.
A record loads, but a link to another record is missing — with the warning reference(s) dropped — target resource not loaded yetThe record it links to hadn’t reached Shopify yet. Graftport loads the record without the link rather than failing it outright.Re-run the load. Graftport re-visits exactly the records whose missing link has since arrived and fills it in — you don’t need to re-transform or reset anything. If the warning sticks after a re-run, the linked record isn’t part of the migration; add its resource to the run and load again.
handle has already been takenSlug collision with an existing Shopify product.Edit the mapping’s handle rule (e.g. add a SKU suffix), re-transform, re-load.
A collection loads but its image is missingShopify couldn’t fetch the collection image (dead source URL, timeout, or the link didn’t resolve to an image). Graftport loads the collection without it rather than failing the whole record.Check the source image link opens in a browser. If it does, re-run the load; otherwise fix the image in the source and re-run, or set it manually in Shopify.
Inventory not appearing on the right locationDefault mapping assigns to first active location.Resync locations from the migration page; fork the products mapping if you need per-location split.
Records load but are Draft instead of ActiveSource product status doesn’t map to ACTIVE.Check the mapping’s status field; default expects enabled.
An order re-load succeeds with the warning field(s) could not be updatedThis particular push couldn’t tell whether the order’s products/prices had changed, so it took the safe route and only updated what Shopify allows in place. Happens on the first re-load of orders migrated before rebuilds were supported, and on any run using Update specific fields only.Run the load again. The first run records what the order looked like, so the second can tell exactly what moved and rebuild the order if it needs to. If you’re using Update specific fields only, that’s working as intended — switch to Overwrite everything when you want line-item and price corrections applied.
Orders were deleted and re-created, and their staff notification emails fired againExpected when products, quantities, prices, taxes, discounts or payment status changed — Shopify can’t alter those on an existing order, so Graftport rebuilds it. The order number and date are preserved.Nothing to fix. To see it coming next time, run a dry run first: it reports how many orders would be rebuilt without touching Shopify. Disable Settings → Notifications → Staff notifications before large re-runs.
An order was rebuilt and a manual refund or staff note made in Shopify is goneA rebuild deletes the order and re-creates it from the mapping, so anything added inside Shopify after the migration isn’t part of it.Re-apply the change in Shopify admin. To avoid it on future runs, use Update specific fields only so orders are never rebuilt, and make line-item corrections in the source system before the final cut-over.
Some orders fail with transactions cannot be created on archived orderThe destination order already exists from a prior cut-over and got archived.Switch conflict strategy to skip, or re-create on a fresh destination store.
Staff inboxes flooded with “New order” emails during an order migrationShopify emails staff a notification for every order Graftport loads.Disable Settings → Notifications → Staff notifications before the load, re-enable after. See Before migrating orders.

Updating an existing Shopify store

These only apply to a migration whose destination is the store it reads from — see Update an existing Shopify store.

Error / symptomLikely causeWhat to do
SAME_STORE_NO_IDENTITY on a recordGraftport couldn’t tell which record in your store this row refers to, so it refused to push rather than risk creating a duplicate. Almost always a row from an uploaded CSV, which has no Shopify id.Nothing to fix on the record itself. If you meant to edit existing records, remove the CSV feed and use the store’s own feed. If you meant to add records, that needs a normal migration into the store, not an in-place update.
”Skip existing records” isn’t available in the run dialogEvery record in this kind of migration already exists, so skipping them would skip everything.Narrow the run with a field filter (only the fields you want to change) or a row filter (only the records you want to touch).
The run is refused because discount codes are enabledDiscount codes can’t be updated in place yet — Shopify has no update mutation wired for them.Disable the discount code resource on the migration, or scope the run to the other resources.
Stock levels didn’t changeIn-place updates never write inventory, on purpose — the safe default is to leave stock alone.Adjust stock in your Shopify admin or with a dedicated inventory tool.
Product images unchanged after a runIn-place updates never re-send images, so Shopify can’t duplicate your existing media.Change images in your Shopify admin.
Purge and duplicate cleanup are missing from the migrationBoth are disabled for this kind of migration — they would delete records from your live store.Remove records from your Shopify admin instead.
Old product URLs 404 after a run that changed handlesChanging a handle changes the URL; Shopify doesn’t redirect automatically.Use Emit redirects on the migration to create 301s from the old paths.

Run lifecycle

Error / symptomLikely causeWhat to do
Run stays Pending for minutesWorker is busy or down.Check the platform status page. Don’t queue more runs for the same migration — you’ll just deepen the backlog.
Run is running but counts don’t moveThe source stopped responding mid-extract (a hung or very slow endpoint).Graftport now bounds each source fetch: a stalled extract fails on its own with a “source page fetch exceeded …” error instead of hanging forever, and other resources in the run continue. Check the source is reachable, then re-run — re-running is safe.
Run says StalledA step has been running for more than ten minutes without moving a single record.Stalled runs rarely recover on their own. Cancel the run and start a new one — records that already landed stay where they are and the new run picks up from there.
A resource finished transforming but its progress still reads 0%Nothing is wrong with the reading. Transforming prepares records; loading is what puts them in the destination, and the bar measures records that arrived.Look at that resource’s Load step. If it hasn’t started, the run is still working or stalled; if it failed, the Errors tab says why.
A dry run finished but the bar says 0 in the destinationIt shouldn’t — a dry run’s bar is labelled cleared to load, because a dry run deliberately writes nothing.Read the Dry run summary on the run: it lists what a real run would create, update, re-create and skip. Start a real run when the numbers look right.
Run is Failed but no item shows an errorA startup-time validation failed (e.g. credentials missing).Look at the run’s top-level error, not the items. Fix the cause; new runs unblock.
Load shows Succeeded but 0 loaded right after you stopped a purgeStopping a purge partway leaves the records past the stop point still loaded and unchanged, so a normal load has nothing new to push.Graftport now says so on the run — “Nothing to load: N records already loaded and unchanged” — instead of a bare green success. Use Resume purge on the migration to finish clearing those records, or run a Load to re-create the ones the purge already deleted.
After stopping a purge, the summary shows records still loadedA stopped purge is partial by design — records it already deleted are reloadable, records it hadn’t reached yet are untouched.The purge summary reports how many records remain loaded and offers Resume purge to finish. Resuming picks up exactly where it stopped.
A finished run, purge, or redirect summary banner stays on the migration pageThe banner keeps the last job’s outcome visible until you’ve seen it.Click the on the right of the banner to dismiss it. It stays dismissed across reloads; the next run, purge, or redirect emission shows its own summary.
Last updated on