Debugging Shopify Liquid templates is notoriously difficult. There's no built-in debugger, no breakpoints, no step-through execution. When something breaks, you're often left staring at a blank page or cryptic error message with no clear path forward.
This guide covers every method for debugging Liquid — from basic techniques to advanced tooling — so you can diagnose and fix issues faster.
Why Is Liquid Hard to Debug?
Liquid is a templating language, not a programming language. It runs server-side on Shopify's infrastructure, which means:
- No browser DevTools — You can't inspect Liquid like you inspect JavaScript
- No console.log — There's no native way to print debug output
- Silent failures — Many errors render as empty strings instead of error messages
- No stack traces — When something breaks, you don't know where
- Server-rendered — Every change requires a page refresh to test
This makes debugging a slow, frustrating process of trial and error.
Method 1: The JSON Filter
The most common debugging technique is outputting objects as JSON:
{{ product | json }}
This renders the entire product object as a JSON string in your HTML. You can then:
- View page source or inspect element
- Copy the JSON output
- Paste into a JSON formatter to read it
Limitations
- Clutters your HTML output
- Easy to forget and leave in production code
- Requires refreshing the page for every change
- Large objects are hard to navigate
- No syntax highlighting or search
Better: Wrap in a script tag
<script>
console.log('Product:', {{ product | json }});
</script>
Now you can view it in browser DevTools console with proper formatting.
Method 2: Shopify Theme Check
Theme Check is Shopify's official linter for Liquid. It catches common errors before you deploy.
Installation
# Via Shopify CLI
shopify theme check
# Or standalone
gem install theme-check
theme-check
What it catches
- Undefined objects and variables
- Deprecated tags and filters
- Missing template files
- Performance issues (too many API calls)
- Translation key errors
Limitations
- Static analysis only — doesn't catch runtime errors
- Can't inspect actual data values
- Runs in terminal, not in browser
- No live debugging
Method 3: Shopify's Built-in Error Messages
Liquid does surface some errors directly in the HTML output. Look for:
Liquid error: undefined method 'title' for nil:NilClass
Liquid syntax error: Unknown tag 'endfor'
How to find them
- View page source (
Cmd+U/Ctrl+U) - Search for "Liquid error" or "Liquid syntax"
- The error message usually indicates the file and line
Common error patterns
| Error | Cause | Fix |
|---|---|---|
undefined method for nil:NilClass |
Accessing property on null object | Add {% if object %} check |
Unknown tag |
Typo in tag name | Check spelling (endif not end if) |
Could not find snippet |
Missing snippet file | Create the file or fix the path |
Invalid JSON |
Malformed JSON in section schema | Validate your JSON syntax |
Method 4: Preview Inspector (Theme Editor)
Shopify's theme customizer has a basic inspector:
- Open theme customizer
- Click on a section
- View available settings and blocks
Limitations
- Only shows section settings, not Liquid objects
- Can't inspect product, cart, or collection data
- No expression evaluation
- No error detection
Method 5: Browser DevTools (for JavaScript)
If your Liquid outputs data for JavaScript consumption, you can debug the JavaScript side:
<script>
window.productData = {{ product | json }};
</script>
Then in browser console:
console.log(productData.title);
console.log(productData.variants[0].price);
Limitations
- Only works for data you explicitly expose
- Can't access Liquid-only objects like
templateorrequest - Requires modifying your code to expose data
Method 6: In-Browser Liquid DevTools
The most comprehensive solution is using dedicated developer tools that run in the browser.
Shopify Theme Devtools is an open-source panel that provides:
Objects Inspector
Browse all Liquid objects in a collapsible tree view:
-
shop— Store settings, currency, locale -
product— Current product with variants, images, metafields -
collection— Collection data with products -
cart— Live cart state with items and attributes -
customer— Logged-in customer data -
template— Current template name and directory -
request— Page URL, host, path
Click any property to copy its Liquid path.
Live Expression Evaluator
Test Liquid expressions without refreshing:
> product.title
"Classic Cotton T-Shirt"
> product.price | money
"$29.99"
> cart.items | size
3
> product.variants | first | json
{"id": 12345, "title": "Small / Blue", ...}
Supports 50+ Liquid filters including money, money_with_currency, img_url, asset_url, and more.
Automatic Error Detection
Scans the page for common Liquid issues:
| Error Type | Example |
|---|---|
| Liquid errors | Liquid error: undefined method 'size' |
| Syntax errors | Liquid syntax error: Unknown tag 'endif' |
| Drop object leaks | #<ProductDrop:0x00007f...> |
| Missing snippets | Could not find snippet 'missing-file' |
| Schema errors | Invalid JSON in section schema |
| JSON filter errors | {"error":"not found"} |
Each error includes a suggested fix.
Cart Debugging
- View live cart state with all items and properties
- Adjust quantities without leaving the panel
- Save and restore cart snapshots
- View cart history with timestamps
Installation
npx shopify-theme-devtools init --inject
Then press Cmd+Shift+D (Mac) or Ctrl+Shift+D (Windows) to open.
Only loads on development themes — safe to commit to your repository.
Common Liquid Errors and Solutions
1. "undefined method for nil:NilClass"
Cause: Accessing a property on an object that doesn't exist.
<!-- This breaks if product is nil -->
{{ product.title }}
Fix: Always check if the object exists first.
{% if product %}
{{ product.title }}
{% endif %}
2. "Unknown tag"
Cause: Typo in a Liquid tag name.
<!-- Wrong -->
{% end if %}
<!-- Correct -->
{% endif %}
3. Drop object leak (#ProductDrop:0x...)
Cause: Outputting a Liquid object without the json filter.
<!-- Wrong — renders as #<ProductDrop:0x...> -->
<script>
const product = {{ product }};
</script>
<!-- Correct -->
<script>
const product = {{ product | json }};
</script>
4. "Could not find snippet"
Cause: Rendering a snippet that doesn't exist.
{% render 'non-existent-snippet' %}
Fix: Check the snippet filename and ensure it's in the snippets/ folder.
5. Empty output (no error)
Cause: Variable is nil or empty, but Liquid doesn't error — it just outputs nothing.
Debug: Use the inspect filter or JSON output:
{{ my_variable | json }}
<!-- Shows "null" if nil, actual value otherwise -->
6. "Invalid JSON in schema"
Cause: Section schema has malformed JSON.
{% schema %}
{
"name": "My Section",
"settings": [
{
"type": "text",
"id": "title"
<!-- Missing comma here -->
"label": "Title"
}
]
}
{% endschema %}
Fix: Validate your JSON at jsonlint.com.
7. Incorrect money formatting
Cause: Using raw price values without the money filter.
<!-- Wrong — outputs "2999" -->
{{ product.price }}
<!-- Correct — outputs "$29.99" -->
{{ product.price | money }}
8. Array index out of bounds
Cause: Accessing an array index that doesn't exist.
<!-- Breaks if product has fewer than 3 images -->
{{ product.images[2].src }}
Fix: Check array size first:
{% if product.images.size > 2 %}
{{ product.images[2].src }}
{% endif %}
Debugging Workflow: A Step-by-Step Process
When you encounter an issue, follow this process:
Step 1: Check for visible errors
Search your page source for "Liquid error" or "Liquid syntax error".
Step 2: Isolate the problem
Comment out sections of code until the error disappears:
{% comment %}
{{ potentially_broken_code }}
{% endcomment %}
Step 3: Inspect the data
Use JSON output or a devtools panel to see what data is actually available:
{{ product | json }}
Step 4: Verify object existence
Add existence checks around the problematic code:
{% if product %}
{% if product.metafields.custom.size > 0 %}
{{ product.metafields.custom | json }}
{% else %}
<!-- No custom metafields -->
{% endif %}
{% else %}
<!-- Product is nil -->
{% endif %}
Step 5: Test expressions incrementally
Break complex expressions into smaller parts:
<!-- Instead of this -->
{{ product.metafields.custom.care_instructions.value | newline_to_br }}
<!-- Test each part -->
{{ product.metafields | json }}
{{ product.metafields.custom | json }}
{{ product.metafields.custom.care_instructions | json }}
Performance Debugging
Some Liquid issues aren't errors — they're performance problems.
Too many API calls
Each time you access all_products, collections, or similar global objects, Shopify makes API calls. Too many calls slow down your page.
<!-- Bad — N+1 query problem -->
{% for product_handle in product_handles %}
{% assign p = all_products[product_handle] %}
{{ p.title }}
{% endfor %}
<!-- Better — use collection or section settings -->
{% for product in collection.products %}
{{ product.title }}
{% endfor %}
Heavy JSON output
Outputting large objects as JSON increases page size:
<!-- Bad — includes all product data -->
{{ product | json }}
<!-- Better — only what you need -->
{
"id": {{ product.id | json }},
"title": {{ product.title | json }},
"price": {{ product.price | json }}
}
Identify slow sections
Use browser DevTools Network tab to check page load time. If pages are slow:
- Check for excessive
forloops - Look for
all_productsorcollectionscalls - Reduce JSON payload size
- Consider lazy loading non-critical content
Debugging Metafields
Metafields are a common source of confusion because they may or may not exist.
Check if a metafield exists
{% if product.metafields.custom.care_instructions %}
{{ product.metafields.custom.care_instructions.value }}
{% else %}
No care instructions available.
{% endif %}
List all metafields
<pre>{{ product.metafields | json }}</pre>
Access nested metafield values
For JSON metafields:
{% assign data = product.metafields.custom.specs.value %}
{{ data.weight }}
{{ data.dimensions }}
Summary
| Method | Best for | Limitations |
|---|---|---|
| `\ | json` filter | Quick data inspection |
| Theme Check | Pre-deploy linting | Static only, no runtime |
| Browser DevTools | JavaScript debugging | Can't access Liquid objects |
| Page source search | Finding error messages | No object inspection |
| Shopify Theme Devtools | Full debugging workflow | Requires installation |
For most developers, combining Theme Check (for linting) with an in-browser devtools panel (for runtime debugging) provides the most complete debugging experience.
Additional Resources
- Shopify Liquid Reference
- Theme Check Documentation
- Shopify Theme Devtools
- LiquidJS Documentation (for understanding filter behavior)
What debugging techniques do you use for Shopify Liquid? Share your tips in the comments.
Tags: #shopify #liquid #debugging #webdev #ecommerce #tutorial #devtools
Top comments (0)