gatsbyjs/gatsby · error · HttpError

response.statusText

Error message

response.statusText

What it means

Thrown by createGraphqlClient in gatsby-source-shopify when the Shopify Admin API responds with a non-ok status that is not retried (i.e. not a 5xx within the backoff window). The error message is response.statusText from node-fetch, and the full Response is attached as error.response for inspection. Common status codes: 401 (bad password/token), 403 (scope mismatch), 404 (wrong apiVersion/storeUrl), 429 (rate limit exceeded the backoff budget).

Source

Thrown at packages/gatsby-source-shopify/src/clients.ts:38

      method: `POST`,
      headers: {
        "Content-Type": `application/json`,
        "X-Shopify-Access-Token": options.password,
      },
      body: JSON.stringify({
        query,
        variables,
      }),
    })

    if (!response.ok) {
      const waitTime = 2 ** (retries + 1) + 500
      if (response.status >= 500 && waitTime < MAX_BACKOFF_MILLISECONDS) {
        await new Promise(resolve => setTimeout(resolve, waitTime))
        return graphqlFetch(query, variables, retries + 1)
      }

      throw new HttpError(response)
    }

    const json = await response.json()
    return json.data as T
  }

  return { request: graphqlFetch }
}

export function createRestClient(options: IShopifyPluginOptions): IRestClient {
  const baseUrl = `https://${options.storeUrl}/admin/api/${options.apiVersion}`

  async function shopifyFetch(
    path: string,
    fetchOptions = {
      headers: {
        "X-Shopify-Access-Token": options.password,
      },

View on GitHub (pinned to 8b06340921)

Solutions

  1. Inspect error.response.status and error.response.statusText to identify the failure class.
  2. For 401/403: regenerate the Shopify Admin API access token and verify the app's access scopes include the queried resources.
  3. For 404: confirm storeUrl (no protocol/scheme) and apiVersion (e.g. 2024-01) match a supported Shopify Admin API version.
  4. For 429: reduce parallelism or wait for the rate-limit window to reset; the plugin only retries 5xx, so throttle upstream.

Example fix

// before
resolve: `gatsby-source-shopify`,
options: { storeUrl: `https://mystore.myshopify.com`, password: process.env.SHOPIFY_KEY }

// after
resolve: `gatsby-source-shopify`,
options: { storeUrl: `mystore.myshopify.com`, password: process.env.SHOPIFY_ADMIN_TOKEN, apiVersion: `2024-01` }
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

function isHttpError(e): e is Error & { response: import('node-fetch').Response } { return e instanceof Error && 'response' in e && typeof (e as any).response?.status === 'number' }

Try / catch

try { await client.request(query, variables) } catch (e) { if (isHttpError(e)) { if (e.response.status === 401) reporter.panic('Shopify token invalid/expired'); if (e.response.status === 404) reporter.panic('Shopify storeUrl or apiVersion wrong') } throw e }

Prevention

When it happens

Trigger: Wrong Shopify storeUrl or apiVersion producing 404; invalid or revoked access token producing 401; app uninstalled mid-build producing 403; rate-limit 429 that exceeded the MAX_BACKOFF_MILLISECONDS window; Shopify API version deprecated and removed.

Common situations: Token expired or app was uninstalled; apiVersion string mistyped or pinned to an old version that Shopify removed; storeUrl includes https:// or trailing slash; password field set to the API key instead of the secret; CI using a stale env var.

Related errors


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