Shopify Debugging & Troubleshooting
Expert guidance for debugging Shopify themes, apps, and API integrations with practical solutions to common issues.
When to Use This Skill
Invoke this skill when:
- Debugging Liquid template errors or syntax issues
- Troubleshooting theme rendering problems
- Fixing API errors (GraphQL, REST)
- Debugging JavaScript errors in themes or apps
- Investigating cart or checkout issues
- Resolving webhook delivery failures
- Troubleshooting OAuth authentication problems
- Debugging theme preview or customizer issues
- Investigating slow page loads or performance problems
- Fixing metafield or metaobject access errors
- Resolving CORS or network request issues
Core Capabilities
1. Liquid Debugging
Debug Liquid template errors and rendering issues.
Enable Theme Preview:
1. Go to Online Store > Themes
2. Click "Customize" on your theme
3. Open browser DevTools (F12)
4. Check Console for Liquid errors
Common Liquid Errors:
Syntax Error:
{# ❌ Error: Missing endif #}
{% if product.available %}
<button>Add to Cart</button>
{# Missing {% endif %} #}
{# ✅ Fixed #}
{% if product.available %}
<button>Add to Cart</button>
{% endif %}
Undefined Variable:
{# ❌ Error: product undefined on collection page #}
{{ product.title }}
{# ✅ Fixed: Check context #}
{% if product %}
{{ product.title }}
{% else %}
{# Not on product page #}
{% endif %}
Invalid Filter:
{# ❌ Error: Unknown filter #}
{{ product.price | format_money }}
{# ✅ Fixed: Correct filter name #}
{{ product.price | money }}
Debug Output:
{# Output variable as JSON #}
{{ product | json }}
{# Check variable type #}
{{ product.class }}
{# Check if variable exists #}
{% if product %}
Product exists
{% else %}
Product is nil
{% endif %}
{# Output all properties #}
<pre>{{ product | json }}</pre>
Console Logging from Liquid:
<script>
console.log('Product ID:', {{ product.id }});
console.log('Product data:', {{ product | json }});
console.log('Cart:', {{ cart | json }});
</script>
2. JavaScript Debugging
Debug JavaScript errors in themes and apps.
Browser Console:
// Log to console
console.log('Debug:', variable);
console.error('Error:', error);
console.warn('Warning:', warning);
// Log object properties
console.table(data);
// Group related logs
console.group('Cart Operations');
console.log('Cart ID:', cartId);
console.log('Items:', items);
console.groupEnd();
// Time operations
console.time('API Call');
await fetch('/api/data');
console.timeEnd('API Call');
// Stack trace
console.trace('Execution path');
Breakpoints:
// Programmatic breakpoint
debugger;
// Set in browser DevTools:
// Sources tab > Click line number
Error Handling:
// ❌ Unhandled error
const data = await fetch('/api/data').then(r => r.json());
// ✅ Proper error handling
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log('Data:', data);
} catch (error) {
console.error('Failed to fetch data:', error);
// Show user-friendly error message
alert('Failed to load data. Please try again.');
}
Network Debugging:
1. Open DevTools > Network tab
2. Filter by XHR or Fetch
3. Click request to see:
- Request headers
- Request payload
- Response headers
- Response body
- Timing information
3. API Error Debugging
Debug GraphQL and REST API errors.
GraphQL Errors:
Error response format:
{
"errors": [
{
"message": "Field 'invalidField' doesn't exist on type 'Product'",
"locations": [{ "line": 3, "column": 5 }],
"path": ["product", "invalidField"],
"extensions": {
"code": "FIELD_NOT_FOUND",
"typeName": "Product"
}
}
],
"data": null
}
Check for errors BEFORE accessing data:
const response = await fetch(graphqlEndpoint, {
method: 'POST',
headers: {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, variables }),
});
const { data, errors } = await response.json();
// ✅ Always check errors first
if (errors) {
console.error('GraphQL Errors:');
errors.forEach(error => {
console.error('Message:', error.message);
console.error('Location:', error.locations);
console.error('Path:', error.path);
console.error('Code:', error.extensions?.code);
});
throw new Error(errors[0].message);
}
// Now safe to use data
console.log('Products:', data.products);
Common GraphQL Errors:
Authentication Error:
{
"errors": [{
"message": "Access denied",
"extensions": { "code": "UNAUTHENTICATED" }
}]
}
Fix: Check access token:
// Verify token is valid
const token = 'shpat_...';
// Check token format (should start with shpat_)
if (!token.startsWith('shpat_')) {
console.error('Invalid token format');
}
// Verify in headers
headers: {
'X-Shopify-Access-Token': token, // ✅ Correct header
'Authorization': `Bearer ${token}`, // ❌ Wrong for Admin API
}
Field Not Found:
{
"errors": [{
"message": "Field 'invalidField' doesn't exist on type 'Product'"
}]
}
Fix: Check field name in API docs:
# ❌ Wrong field name
query {
product(id: "gid://shopify/Product/123") {
invalidField
}
}
# ✅ Correct field name
query {
product(id: "gid://shopify/Product/123") {
title
handle
status
}
}
Rate Limit Error:
// Check rate limit header
const response = await fetch(graphqlEndpoint, options);
const rateLimit = response.headers.get('X-Shopify-GraphQL-Admin-Api-Call-Limit');
console.log('Rate limit:', rateLimit); // "42/50"
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
}
REST API Errors:
404 Not Found:
const response = await fetch(`https://${shop}/admin/api/2025-10/products/999999.json`, {
headers: { 'X-Shopify-Access-Token': token },
});
if (response.status === 404) {
console.error('Product not found');
// Check:
// 1. Product ID is correct
// 2. Product exists in store
// 3. Using correct endpoint
}
422 Unprocessable Entity:
{
"errors": {
"title": ["can't be blank"],
"price": ["must be greater than 0"]
}
}
Fix: Validate input:
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'X-Shopify-Access-Token': token,
'Content-Type': 'application/json',
},
body: JSON.stringify({
product: {
title: '', // ❌ Empty title
price: -10, // ❌ Negative price
},
}),
});
if (response.status === 422) {
const { errors } = await response.json();
console.error('Validation errors:', errors);
// Fix data
const validProduct = {
title: 'Product Name', // ✅ Valid title
price: 19.99, // ✅ Valid price
};
}
4. Cart Debugging
Debug cart and Ajax API issues.
Cart Not Updating:
// ❌ Common mistake: Wrong variant ID
fetch('/cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: '123', // ❌ Wrong: using product ID instead of variant ID
quantity: 1,
}),
});
// ✅ Fixed: Use variant ID
fetch('/cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 123456789, // ✅ Variant ID (numeric)
quantity: 1,
}),
})
.then(response => {
if (!response.ok) {
return response.json().then(err => {
console.error('Cart error:', err);
throw err;
});
}
return response.json();
})
.then(item =>