Skip to main content
Debugging

Debugging Shopify Invalid Schema Errors Step by Step

Diagnose invalid Shopify section schema by separating JSON syntax, schema rules, setting IDs, block references, and Liquid rendering into a repeatable workflow.

6 min read
ShopifySchemaJSONDebugging

“Invalid schema” describes several different failures. The JSON may be malformed, the JSON may be valid but violate Shopify's section-schema rules, or the schema may save while the Liquid references IDs that do not exist. Editing random commas often hides the actual category of failure.

This guide uses a deliberately broken promotion section and a layered debugging process. By the end, you will have a small valid section plus a checklist that separates JSON parsing, Shopify validation, Liquid rendering, and theme-editor behaviour.

Prerequisites

Use a duplicate or development theme, not an untested live theme. You need the section file that fails and a text editor that can show matching brackets. Shopify CLI and Theme Check are useful but optional; Shopify's admin code editor also surfaces Theme Check diagnostics.

Keep the official section schema reference nearby. A general JSON validator can prove syntax, but only Shopify-aware tooling can evaluate platform-specific properties and setting rules.

A broken example

The original static HTML is straightforward:

<aside class="promotion">
  <h2>Weekend delivery update</h2>
  <p>Order by noon on Friday for the next dispatch window.</p>
  <a href="/pages/delivery">Delivery details</a>
</aside>

The first attempted schema contains several problems:

{
  "name": "Promotion",
  "settings": [
    {
      "type": "text",
      "id": "Heading Text",
      "label": "Heading",
      "default": "Weekend delivery update",
    },
    {
      "type": "url",
      "id": "link",
      "label": "Link"
    },
    {
      "type": "text",
      "id": "link",
      "label": "Link label"
    }
  ],
  "presets": [
    { "name": "Promotion", "blocks": [{ "type": "notice" }] }
  ]
}

There is a trailing comma after the first default, an invalid setting ID with a space and uppercase characters, a duplicate link ID, and a preset that references a block type the schema never defines. Fixing only the comma produces valid JSON but not a valid Shopify section.

Layer 1: isolate the schema payload

Copy only the text between {% schema %} and {% endschema %}. Do not include the Liquid tags in a JSON validator. Strict JSON requires double-quoted keys and strings, balanced braces and brackets, and no comments or trailing commas.

A fast local syntax check is:

node -e "JSON.parse(require('fs').readFileSync('schema.json', 'utf8')); console.log('valid JSON')"

That command checks syntax only. A result of valid JSON does not mean the section follows Shopify's setting, block, or preset rules.

Layer 2: inspect IDs and references

Use short, descriptive snake-case IDs such as heading, body, and link_label. IDs are the contract between schema and Liquid:

{{ section.settings.link_label }}

The link_label spelling must match exactly. Within a settings array, duplicate IDs are ambiguous and should be fixed rather than worked around in Liquid.

Then check references in both directions:

  • Every section.settings.x should have a section setting with ID x.
  • Every block.settings.x should exist in that block type's settings.
  • Every block type named in a preset should exist in the blocks array.
  • Every preset setting key should refer to a real setting ID.

Layer 3: reduce to a valid complete section

When a large section has many moving parts, keep a backup and reduce it to one setting and one preset. Add groups back until the error returns. Here is the corrected, complete promotion section:

{% style %}
  #shopify-section-{{ section.id }} .promotion {
    padding: 1.5rem;
    border: 1px solid currentColor;
    border-radius: 0.75rem;
  }
{% endstyle %}

<aside
  class="promotion"
  {% if section.settings.heading != blank %}aria-labelledby="PromotionHeading-{{ section.id }}"{% endif %}
>
  {% if section.settings.heading != blank %}
    <h2 id="PromotionHeading-{{ section.id }}">
      {{ section.settings.heading | escape }}
    </h2>
  {% endif %}

  {% if section.settings.body != blank %}
    <div class="rte">{{ section.settings.body }}</div>
  {% endif %}

  {% if section.settings.link_label != blank and section.settings.link != blank %}
    <a href="{{ section.settings.link }}">
      {{ section.settings.link_label | escape }}
    </a>
  {% endif %}
</aside>

{% schema %}
{
  "name": "Promotion",
  "settings": [
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Weekend delivery update"
    },
    {
      "type": "richtext",
      "id": "body",
      "label": "Text",
      "default": "<p>Order by noon on Friday for the next dispatch window.</p>"
    },
    {
      "type": "text",
      "id": "link_label",
      "label": "Link label",
      "default": "Delivery details"
    },
    {
      "type": "url",
      "id": "link",
      "label": "Link"
    }
  ],
  "presets": [
    {
      "name": "Promotion"
    }
  ]
}
{% endschema %}

The schema is strict JSON: it contains no comments, Liquid expressions, or trailing commas. The richtext default includes paragraph HTML because that setting returns rich HTML, and the template outputs it in a div rather than nesting it inside a paragraph.

Layer 4: run Shopify-aware checks

Run this command from the theme directory:

shopify theme check

Theme Check analyzes Liquid and JSON and can flag syntax problems, invalid schema, missing assets, unsupported Liquid, and other theme issues. Its official documentation explains editor and command-line integrations. If the command is not installed, use the current Shopify CLI setup instructions rather than copying an old global-install command from an unrelated tutorial.

Read the first relevant error before responding to later cascading messages. A missing bracket near the top can cause several misleading errors farther down.

Layer 5: separate save errors from runtime errors

A schema save error occurs before the section can be configured. A Liquid runtime error may instead come from the markup, such as an unknown filter or unclosed tag. A third category appears only in the editor: the section saves, but a setting does not update the expected output because its ID or scope is wrong.

Use this order:

  1. Make the schema valid strict JSON.
  2. Resolve Shopify schema diagnostics.
  3. Check Liquid syntax.
  4. Add the section to a development template.
  5. Change each setting and observe the rendered result.

Common schema failures

  • Trailing comma: remove the comma after the final item in every object and array.
  • Comment in JSON: move the explanation outside the schema. Neither // nor Liquid comments belong in JSON.
  • Single quotes: JSON strings require double quotes.
  • Duplicate IDs: rename one setting and update every matching Liquid reference.
  • Invalid default: make sure the default matches the setting type and allowed options.
  • Preset references an unknown block: add the block definition or remove the preset block.
  • Wrong scope: a block setting is read from block.settings, not section.settings.
  • Two schema tags: a section should contain one schema block; combine the definitions.
  • Liquid inside schema: schema is not a place for {{ }} or {% %} expressions.

Expected output and accessibility

With the defaults, the section renders a labelled aside containing a level-two heading and one paragraph. The optional link appears only after both its label and destination exist. The section is fluid by default and does not require a mobile-specific layout.

Schema validity does not prove accessibility. After the file saves, confirm the heading fits the page hierarchy, link text is meaningful, keyboard focus remains visible, and colour choices inherited from the theme meet contrast requirements.

Testing instructions

  1. Add the corrected file to a development theme.
  2. Run shopify theme check and resolve errors related to the file.
  3. Add Promotion through the theme editor; a missing entry usually indicates a preset problem.
  4. Edit each field, clear each optional field, and reload the storefront outside the editor.
  5. View the rendered HTML and verify no empty anchor remains.
  6. Test narrow and wide viewports and tab to the link.
  7. Re-run Theme Check after the final edit, not only after the initial schema save.

Manual verification checklist

  • The text inside the schema tags passes JSON.parse.
  • There are no comments, trailing commas, or Liquid expressions in JSON.
  • Setting IDs are unique, stable, and consistently spelled.
  • All block and preset references resolve.
  • Rich-text defaults contain valid supported HTML.
  • Liquid uses the correct section or block scope.
  • The section appears in the editor and every setting updates it.
  • Theme Check passes for the changed file.
  • Empty values and keyboard interaction are tested.

The schema builder can help assemble and inspect settings before you paste them into a file. The Shopify section schema reference explains the overall structure, while common Shopify development mistakes covers errors beyond schema.

Conclusion

Treat invalid schema as a layered validation problem. Strict JSON is the first gate, Shopify's schema rules are the second, Liquid syntax is the third, and editor behaviour is the final proof. Working through those layers in order is faster and safer than repeatedly changing punctuation in the full file.

Found this helpful?

Share it with your network!

Ready to Convert HTML to Liquid?

Try our free HTML to Liquid converter and build your Shopify themes faster.

Try HTML2Liquid Now