Shopify/liquid · error · Liquid::SyntaxError

errors.syntax.include

errors.syntax.include

Error message

options[:locale].t("errors.syntax.include")

What it means

Include#lax_parse raises SyntaxError when the {% include %} markup doesn't match its expected grammar: a template name (string literal or variable) optionally followed by 'with x' or 'for x' and attribute assignments. Falling into the else branch means the whole markup was unparseable even in lenient mode.

Solutions

  1. Give the include a valid name: {% include 'header' %} or {% include partial_name %}
  2. Use the supported modifiers: {% include 'card' with product %} or {% include 'item' for items %} (not both mixed arbitrarily)
  3. Check for unclosed quotes or duplicated tokens in the tag

Example fix

// before
{% include %}
// after
{% include 'product_card' %}
Defensive patterns

Strategy: validation

Validate before calling

valid = markup =~ /\A\s*(\"[^\"]+\"|'[^']+'|[\w\-\.]+)(\s+(with|for)\s+\S+)?(\s*\w+\s*=\s*\S+)*\s*\z/
raise Liquid::SyntaxError, 'invalid include markup' unless valid

Type guard

def valid_include_tag?(markup)
  !markup.to_s.strip.empty? && markup !~ /\A\s*\z/
end

Try / catch

begin
  Liquid::Template.parse(template)
rescue Liquid::SyntaxError => e
  logger.error("Invalid include tag: #{e.message}")
  fallback_template
end

Prevention

When it happens

Trigger: Markup like {% include %} (no name), {% include 'a' 'b' %}, or include tags with stray tokens that match neither the TemplateName+with/for pattern nor TagAttributes.

Common situations: Deleted partial name after refactoring; quoting/typo issues such as {% include 'partial.html %} (unclosed quote); copying {% render %} syntax that include doesn't accept.

Related errors


AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08). Data as JSON: /api/errors/72aa546c431d05ac. Report an issue: GitHub.

Appendix: source

Thrown at lib/liquid/tags/include.rb:135

    def lax_parse(markup)
      if markup =~ SYNTAX
        template_name = Regexp.last_match(1)
        with_or_for   = Regexp.last_match(3)
        variable_name = Regexp.last_match(4)

        @alias_name         = Regexp.last_match(6)
        @variable_name_expr = variable_name ? parse_expression(variable_name) : nil
        @template_name_expr = parse_expression(template_name)
        @is_for_loop        = (with_or_for == FOR)
        @attributes         = {}

        markup.scan(TagAttributes) do |key, value|
          @attributes[key] = parse_expression(value)
        end

      else
        raise SyntaxError, options[:locale].t("errors.syntax.include")
      end
    end

    class ParseTreeVisitor < Liquid::ParseTreeVisitor
      def children
        [
          @node.template_name_expr,
          @node.variable_name_expr,
        ] + @node.attributes.values
      end
    end
  end
end

View on GitHub (pinned to 807d45a6b3)