Agent Skills: Shopify Common Errors

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/shopify-common-errors

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/shopify-pack/skills/shopify-common-errors

Skill Files

Browse the full folder contents for shopify-common-errors.

Download Skill

Loading file tree…

plugins/saas-packs/shopify-pack/skills/shopify-common-errors/SKILL.md

Skill Metadata

Name
shopify-common-errors
Description
|

Shopify Common Errors

Overview

Quick-reference guide for the most common Shopify API errors with real error messages, causes, and fixes.

Prerequisites

  • Shopify app with API credentials configured
  • Access to application logs or console output

Instructions

Step 1: Identify the Error Type

Check whether the error is an HTTP status code error or a GraphQL userErrors response.

Step 2: Match Error Below and Apply Fix


401 Unauthorized

Actual Shopify Response:

{
  "errors": "[API] Invalid API key or access token (unrecognized login or wrong password)"
}

Causes:

  • Access token expired (merchant uninstalled and reinstalled)
  • Wrong X-Shopify-Access-Token header
  • Using a Storefront API token for Admin API or vice versa

Fix:

# Verify token format:
# Admin API token: shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (32 hex chars)
# Storefront API token: different format, starts with shpat_ too
curl -s -o /dev/null -w "%{http_code}" \
  -H "X-Shopify-Access-Token: $SHOPIFY_ACCESS_TOKEN" \
  "https://your-store.myshopify.com/admin/api/2024-10/shop.json"
# Should return 200

403 Forbidden

Actual Shopify Response:

{
  "errors": "This action requires merchant approval for read_orders scope."
}

Cause: Your app's access token lacks the required scope.

Fix: Add the needed scope to your app config and re-trigger OAuth:

# shopify.app.toml
[access_scopes]
scopes = "read_products,write_products,read_orders,write_orders"

404 Not Found

Actual Shopify Response:

{
  "errors": "Not Found"
}

Causes:

  • Wrong API version in URL
  • Resource was deleted
  • Store domain is incorrect

Fix:

# Verify the API version exists
curl -s "https://your-store.myshopify.com/admin/api/2024-10/shop.json" \
  -H "X-Shopify-Access-Token: $TOKEN"

# Check available API versions
curl -s "https://your-store.myshopify.com/admin/api/versions.json" \
  -H "X-Shopify-Access-Token: $TOKEN"

422 Unprocessable Entity

Actual Shopify Responses:

{
  "errors": {
    "title": ["can't be blank"],
    "handle": ["has already been taken"]
  }
}
{
  "errors": {
    "base": ["Product cannot be saved: Title is too long (maximum is 255 characters)"]
  }
}

Common 422 triggers:

  • Missing required fields (title, etc.)
  • Duplicate handle/slug
  • Invalid metafield type
  • Price format issues (must be string like "29.99")
  • Invalid country/province codes

Fix: Check the errors object or userErrors array for specific field-level messages.


429 Too Many Requests (Rate Limited)

REST API Response:

HTTP/1.1 429 Too Many Requests
Retry-After: 2.0

GraphQL Response (in body, returns 200):

{
  "errors": [
    {
      "message": "Throttled",
      "extensions": {
        "code": "THROTTLED",
        "documentation": "https://shopify.dev/api/usage/rate-limits"
      }
    }
  ],
  "extensions": {
    "cost": {
      "requestedQueryCost": 752,
      "actualQueryCost": null,
      "throttleStatus": {
        "maximumAvailable": 2000,
        "currentlyAvailable": 0,
        "restoreRate": 100
      }
    }
  }
}

Fix: See shopify-rate-limits skill for complete backoff implementation.


GraphQL userErrors (200 with Errors)

Critical: Shopify returns HTTP 200 even when mutations fail.

{
  "data": {
    "productCreate": {
      "product": null,
      "userErrors": [
        {
          "field": ["title"],
          "message": "Title can't be blank",
          "code": "BLANK"
        }
      ]
    }
  }
}

Always check userErrors after every mutation:

const response = await client.request(mutation, { variables });
const result = response.data.productCreate;

if (result.userErrors.length > 0) {
  // These are validation errors, NOT HTTP errors
  for (const err of result.userErrors) {
    console.error(`Field ${err.field?.join(".")}: ${err.message} (${err.code})`);
  }
  throw new Error("Shopify validation failed");
}

5xx Server Errors

Shopify internal errors — not your fault, but you must handle them.

{
  "errors": "Internal Server Error"
}

Fix: Retry with exponential backoff. Include the X-Request-Id header value when reporting to Shopify support.

// The X-Request-Id header is in every Shopify response
const requestId = error.response?.headers?.["x-request-id"];
console.error(`Shopify 500 error. Request ID: ${requestId}`);

Output

  • Error identified by HTTP status or GraphQL userErrors
  • Root cause determined
  • Fix applied and verified

Error Handling

| Status | Name | Retryable | Action | |--------|------|-----------|--------| | 401 | Unauthorized | No | Re-authenticate, verify token | | 403 | Forbidden | No | Add missing scope, re-OAuth | | 404 | Not Found | No | Check URL, API version, resource ID | | 422 | Unprocessable | No | Fix validation errors in request body | | 429 | Throttled | Yes | Backoff using Retry-After header | | 500 | Server Error | Yes | Retry with backoff, report X-Request-Id | | 503 | Unavailable | Yes | Shopify is overloaded, retry later |

Examples

Quick Diagnostic Script

#!/bin/bash
STORE="your-store.myshopify.com"
TOKEN="$SHOPIFY_ACCESS_TOKEN"
VERSION="2024-10"

echo "=== Shopify Diagnostic ==="

# 1. Test auth
echo -n "Auth: "
curl -s -o /dev/null -w "%{http_code}" \
  -H "X-Shopify-Access-Token: $TOKEN" \
  "https://$STORE/admin/api/$VERSION/shop.json"
echo ""

# 2. Check scopes
echo "Scopes:"
curl -s -H "X-Shopify-Access-Token: $TOKEN" \
  "https://$STORE/admin/oauth/access_scopes.json" | python3 -m json.tool

# 3. Check API versions
echo "API Versions:"
curl -s -H "X-Shopify-Access-Token: $TOKEN" \
  "https://$STORE/admin/api/versions.json" | python3 -c "
import json, sys
versions = json.load(sys.stdin)['supported_versions']
for v in versions[:5]:
    print(f'  {v[\"handle\"]} {\"(latest)\" if v.get(\"latest\") else \"\"}')"

# 4. Shopify status
echo "Shopify Status: https://www.shopifystatus.com"

Resources

Next Steps

For comprehensive debugging, see shopify-debug-bundle.