Debugging a mapping
Most mapping problems fall into three categories: a JSONata expression that crashes on a specific row, output that loads but produces the wrong shape in Shopify, and a transform that succeeds but a downstream load rejects. This page shows how to diagnose each.
The debugging loop
The fastest cycle is editor → sample → inspect:
- Open the mapping in the editor (Migration → Sources → expand the source → Open mapping).
- Click the Row 1 of 5 control in the Preview header and search for the failing record by its ID.
- Read the Preview — it shows what Graftport would actually send to Shopify, and says so above the payload when the record would be rejected.
- Fix the expression; the preview re-evaluates as you type.
- Once the output looks right, publish a new version.
- Run transform-only scoped to that resource to re-prepare the records.
See Mappings → The mapping editor for the editor UI in detail.
Finding the failing row
A transform run that completes with errors records the reason against every row that failed. From the run detail page:
- Open the Errors tab. Failures are grouped by cause, with a count on each group, so twelve rows that broke the same way read as one problem rather than twelve.
- Expand a group. It says what happened, which field is at fault, and lists the affected records with their source ID, the value that broke and the detail Shopify or JSONata returned.
- Take a source ID from the list into the editor’s record picker and reproduce it against the live expression.
Errors persist across runs. You can open a run from last week to examine what failed even after you’ve fixed the mapping — useful for regression checks.
Common JSONata errors
| Error text | Meaning | Fix |
|---|---|---|
instance member of undefined | The expression references a field path that doesn’t exist on this row (e.g. $.weight_unit when the product has no weight). | Guard with a conditional: $.weight_unit ? $.weight_unit : "kg". |
cannot evaluate function | A function name is misspelled or missing the $ prefix. | Check the function name against the JSONata reference. |
cannot cast type 'null' to number | A numeric operation received null (often from an optional field). | Use $number($.field ?? 0). |
stack overflow | A recursive expression or a very deep nested structure. | Flatten the expression; avoid deeply nested $map inside $map. |
Output loads but looks wrong in Shopify
If the transform succeeds but the Shopify record is wrong, the issue is in the mapping’s output shape, not in a runtime error.
Inspect a staged record
Open Data in the sidebar, pick the migration and the resource, and switch to Mapped output. Find the record — filter on its ID if the list is long. That is the exact Shopify-shaped payload Graftport would send. See Data explorer.
Compare to the expected Shopify shape
Open the Resource mappings page for the resource type. The table there lists every Shopify field and how the default mapping populates it.
Find the divergence
Open the record. The panel shows the source record above the mapped output, so you can read the field on both sides at once and see whether the wrong value came from the source or from the mapping.
Fix the mapping expression
Click Open in the mapping editor on a failed record, or open the mapping and step to that record in the Preview header. Correct the expression for the wrong field.
Publish and re-transform
Publish creates a new mapping version and the migration moves onto it. Run transform-only scoped to this resource to re-stage all rows with the corrected version.
Load rejects a record
Load errors come from Shopify’s API. They appear on the run item’s load phase. Common cases:
| Error | Cause | Fix |
|---|---|---|
handle has already been taken | A product with the same Shopify handle exists on the destination. | Edit the mapping’s handle field to add a suffix (e.g. SKU-based). Re-transform, re-load. |
Access denied for write_products | The destination token is missing the required scope. | Reissue the token with the correct scope; update destination credentials. |
SHOPIFY_BUNDLES_NOT_ENABLED | A bundle record was pushed but the destination store doesn’t have the Shopify Bundles app installed. | Install the Shopify Bundles app on the destination store and re-run. |
Value is too long (maximum is 255 characters) | A mapped string field exceeds Shopify’s field length limit. | Add a truncation expression: $substring($.long_field, 0, 255). |
See Troubleshooting → Common errors for a fuller triage table.
Mapping version mismatch
If records are staging with a payload that doesn’t match what’s in the editor, the usual cause is that you never published — the editor holds an unsaved draft and runs are still using the last published version.
The bar at the top of the editor tells you which it is: it reads
v7 · published when the editor matches the live version, and
v7 · unsaved changes when it doesn’t. Publish v8 turns the draft
into the version the next run uses; nothing you type takes effect
before that.
There is no separate pinning step. Publishing moves the migration onto the new version automatically. A run, though, pins the version it started with and keeps it for the whole run — so publishing mid-run changes nothing about the run in flight. The version each resource used is on the run’s Configuration tab.
After publishing, re-run transform for that resource to re-stage its records with the new version.
See Mappings → Templates & versions for how versioning and pinning work.