From shopify-pack
Diagnoses common Shopify API errors (401, 403, 422, 429, GraphQL) with real responses, causes, and fixes like curl tests and scope reconfiguration.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin shopify-packThis skill is limited to using the following tools:
Quick-reference guide for the most common Shopify API errors with real error messages, causes, and fixes.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
Quick-reference guide for the most common Shopify API errors with real error messages, causes, and fixes.
Check whether the error is an HTTP status code error or a GraphQL userErrors response.
Actual Shopify Response:
{
"errors": "[API] Invalid API key or access token (unrecognized login or wrong password)"
}
Causes:
X-Shopify-Access-Token headerFix:
# 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
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"
Actual Shopify Response:
{
"errors": "Not Found"
}
Causes:
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"
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:
Fix: Check the errors object or userErrors array for specific field-level messages.
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.
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");
}
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}`);
| 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 |
#!/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"
For comprehensive debugging, see shopify-debug-bundle.