{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreiaqxukiwvlazbla5evvi6eljanvbf6us4heahxc5pzaaqz26x2ham",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mpd35piem722"
  },
  "path": "/q00tar00/stop-guessing-why-your-shopify-product-csv-import-failed-d8a",
  "publishedAt": "2026-06-28T03:27:18.000Z",
  "site": "https://dev.to",
  "tags": [
    "shopify",
    "python",
    "cli",
    "csv",
    "https://github.com/q00tar00/shopify-csv-preflight"
  ],
  "textContent": "You exported a product CSV, edited it in Excel or Google Sheets, and uploaded it to Shopify.\nShopify shows a generic error — or worse, it _silently_ imports the wrong thing: a handle gets\noverwritten, a variant attaches to the wrong product, half your rows go missing. You find out\ndays later from a customer.\n\n**Shopify CSV Preflight Validator** checks the file _before_ you upload it. It runs locally on your\nmachine, never touches your store, needs no API key, and returns three things:\n\n  * `fixed_products.csv` — a safe copy with the unambiguous, mechanical mistakes already corrected.\n  * `errors.csv` — a machine-readable list of every finding (row, rule, severity, suggested fix).\n  * `report.md` — a human-readable report you can read in 30 seconds.\n\n\n\nNo login. No upload of your catalog to a third party. Just a file in, a verdict out.\n\n##  Why CSV imports fail (and why the error message doesn't help)\n\nShopify's product CSV import is a two-stage process: it validates the file, then applies rows.\nA file can pass the upload dialog and still misbehave on apply. The most common ways merchants get\nburned:\n\n  1. **A spreadsheet adds a UTF-8 BOM** to the first cell. The first header (`Title`) becomes invisible-garbage + `Title`, so Shopify can't find the title column.\n  2. **Header case / legacy names drift.** `title` instead of `Title`, `Handle` instead of `URL handle`. Some get ignored, some get rejected.\n  3. **A variant row loses its parent handle.** Shopify can't tell which product the variant belongs to.\n  4. **Two product rows share one handle.** Shopify silently keeps one and overwrites/merges the other.\n  5. **Image alt text with no image URL, negative prices, compare-at prices below the real price** — small data bugs that ship to your live storefront.\n\n\n\nThese are not exotic. They're what happens every time a human edits a CSV in a spreadsheet.\n\n##  What the tool actually does — a real run\n\nHere is a messy export with several of the problems above. Running:\n\n\n\n    csv-preflight check messy-product-import-sample.csv --out-dir ./out --lang en\n\n\nproduces this `report.md` (verbatim):\n\n\n\n    # Shopify CSV Preflight Report\n\n    - Summary: scanned rows 4 / product groups 3 / 6 critical / 8 warning / 2 auto-fixed (proven) / 1 suggested\n\n    ## Critical (fix before import)\n    - [F01a] file: UTF-8 BOM detected at file start.\n    - [F03a] file: Header 'title' differs only by case from a known column.\n    - [R02] row 2: Variant/image row is missing the parent URL handle.\n    - [R03] row 1: 2 product-start rows share handle 'aurora-hoodie' (rows 1, 3).\n    - [R03] row 3: 2 product-start rows share handle 'aurora-hoodie' (rows 1, 3).\n    - [R11] row 4: Image alt text present but image URL is empty.\n\n    ## Warning (review recommended)\n    - [R07] row 4: inventory_policy 'maybe' is not a documented value (deny/continue).\n    - [R08] row 4: Inventory tracker 'shopify' set but inventory quantity is empty/non-numeric.\n    - [R10] row 1: Compare-at price 3900.0 <= price 4800.0.\n    - [R10] row 4: Price '-1800' is negative.\n    - ... (fulfillment-service defaults, etc.)\n\n    ## Auto-fixed (proven)\n    - [F01a] file: UTF-8 BOM detected at file start.\n    - [F03a] file: Header 'title' differs only by case from a known column.\n\n    ## Not checked\n    - Not checked by this tool: image URL public reachability, handle overwrite/ignore\n      against an existing store, metafield product reference resolution, and option position\n      consistency with existing products.\n\n\nThe exit code is non-zero when criticals are present, so you can wire it into a script and stop\na bad upload automatically.\n\n###  What got fixed automatically\n\nTwo classes of mistake are unambiguous and safe to fix mechanically, so the tool writes them into\n`fixed_products.csv` for you:\n\n  * **BOM removed** from the file start.\n  * **Header case normalized** (`title` → `Title`).\n\n\n\nEverything else — missing handles, duplicate handles, negative prices — is a _judgment call_ , so the\ntool **reports it but never silently rewrites your data**. You stay in control of your catalog.\n\n###  Honest about its limits\n\nThe report always prints a **Not checked** section. The tool reads a file; it does not connect to\nyour store. It cannot know whether an image URL is publicly reachable, whether a handle will\noverwrite an existing product, or whether a metafield reference resolves. It says so, every time.\nWe would rather under-promise than tell you \"import guaranteed\" and be wrong.\n\n##  Who this is for\n\n  * **Solo merchants** doing a bulk product update before a launch or sale.\n  * **Agencies / freelancers** migrating a client's catalog and wanting a clean handoff.\n  * **Anyone** who has been burned once by a silent partial import and never wants to guess again.\n\n\n\nIt is **product CSV only**. It deliberately refuses files that look like order or customer exports\n(it detects buyer-PII column names and stops) — your customers' data never goes through it.\n\n##  How it compares\n\nThe existing tools (Matrixify, Ablestar) are powerful full migration suites. Merchants who don't\nneed all of that consistently say the same three things: **expensive, slow, and hard to learn.**\n\nThis tool is the opposite end: one command, one purpose — _catch the import-breaking mistakes before\nyou upload_ — with no account and no upload of your catalog.\n\n| Full migration apps | CSV Preflight Validator\n---|---|---\nSetup | Install app, connect store | Run one command locally\nTouches your store | Yes (Admin API) | **No — file in, file out**\nYour catalog leaves your machine | Often | **Never**\nJob | Migrate everything | **Stop a bad import**\n\n##  Try it\n\nIt's on GitHub — read the source, grab a release, run it on your own file:\n\n**https://github.com/q00tar00/shopify-csv-preflight**\n\n\n\n    uv tool install csv-preflight\n    csv-preflight check your-products.csv --out-dir ./out\n\n\nIf a silent partial import has ever bitten you, I'd love to hear what broke — drop a comment or open\nan issue. I'm validating whether this is worth turning into a paid one-shot / Shopify app, and real\nmerchant pain is exactly what I'm looking for.",
  "title": "Stop Guessing Why Your Shopify Product CSV Import Failed"
}