gatsbyjs/gatsby · warning

Could not parse file extension from Shopify image URL: ${url

Error message

Could not parse file extension from Shopify image URL: ${url}

What it means

parseImageExtension splits a Shopify image URL on `?` then looks for the last `.` in the basename. If there is no dot, the URL has no detectable file extension and the function throws. The plugin uses the extension to decide whether to download the image as a local file node (gif is excluded by the caller). A URL with no extension means the helper cannot make that decision.

Source

Thrown at packages/gatsby-source-shopify/src/helpers.ts:148

          createNode,
          createNodeId,
          parentNodeId: node.id,
        })

        image.localFile___NODE = fileNode.id
      }
    }
  }
}

export function parseImageExtension(url: string): string {
  const basename = url.split(`?`)[0]
  const dot = basename.lastIndexOf(`.`)

  if (dot !== -1) {
    return basename.slice(dot + 1)
  } else {
    throw new Error(
      `Could not parse file extension from Shopify image URL: ${url}`
    )
  }
}

View on GitHub (pinned to 8b06340921)

Solutions

  1. Wrap the call in try/catch and skip images whose extension cannot be parsed (do not let one bad URL abort sourcing).
  2. Pre-filter: only call createRemoteFileNode when the URL contains a dot after the query split.
  3. Patch upstream data so originalSrc always carries a real extension.
  4. If SVGs are involved, ensure the URL retains the .svg suffix before it reaches this helper.

Example fix

// before
if (image && parseImageExtension(image.originalSrc) !== `gif`) {
  await createRemoteFileNode({ url: image.originalSrc, ... })
}

// after
try {
  if (image && parseImageExtension(image.originalSrc) !== `gif`) {
    await createRemoteFileNode({ url: image.originalSrc, ... })
  }
} catch (e) {
  reporter.warn(`Skipping image with unparseable extension: ${image?.originalSrc}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

function safeImageExtension(url) {
  const dot = url.split('?')[0].lastIndexOf('.')
  return dot === -1 ? null : url.split('?')[0].slice(dot + 1)
}

Type guard

const hasExtension = (url) => url.split('?')[0].includes('.')

Try / catch

let ext
try { ext = parseImageExtension(url) } catch (e) { reporter.warn(`Skipping image (no extension): ${url}`); continue }

Prevention

When it happens

Trigger: Shopify returns an image URL with no extension (some CDN/S3-style URLs or SVGs served without extension); URL is a base64-like or signature URL where the dot is stripped; URL is malformed/empty; the originalSrc field is a placeholder that lacks an extension.

Common situations: Shopify storefront serving newly uploaded images where the CDN URL omits the extension; custom image transforms returning extensionless URLs; third-party app replacing Shopify image URLs; testing against fixtures with malformed image data.

Related errors


AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13). Data as JSON: /api/errors/2ec6d55842a60f5f. Report an issue: GitHub.