Shopify/liquid · error · Liquid::SyntaxError

errors.syntax.capture

errors.syntax.capture

Error message

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

What it means

The `capture` tag stores rendered output into a variable, so its markup must match Capture::Syntax (a valid variable name). In lax_parse (also used by strict_parse), if the markup does not match, Liquid raises SyntaxError with the localized message 'errors.syntax.capture'. Parsing aborts before any rendering.

Solutions

  1. Give the capture tag exactly one variable name: {% capture greeting %}...{% endcapture %}
  2. Remove '=' or dotted assignment targets from the capture markup; capture only takes a plain name
  3. If you need assignment of an expression instead of block output, use {% assign var = expr %}
  4. Lint templates before deploy to catch malformed capture tags

Example fix

// before
{% capture "headline" %}{{ title | upcase }}{% endcapture %}
// after
{% capture headline %}{{ title | upcase }}{% endcapture %}
Defensive patterns

Strategy: validation

Validate before calling

def valid_capture_markup?(markup)
  markup =~ /\A[\w\-\.]+\z/
end

Try / catch

begin
  Liquid::Template.parse(source)
rescue Liquid::SyntaxError => e
  raise TemplateSyntaxError.new(source: source, cause: e)
end

Prevention

When it happens

Trigger: {% capture %} with empty markup, or markup that is not a single variable name, e.g. `{% capture foo.bar = x %}` or `{% capture "name" %}`.

Common situations: Hand-edited theme templates; copying capture blocks and mangling the variable name; templates generated by string concatenation losing the variable argument; beginners writing `{% capture greeting %}Hello{% endcapture %}` variants with punctuation in the name.

Related errors


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

Appendix: source

Thrown at lib/liquid/tags/capture.rb:38

  # @liquid_syntax_keyword variable The name of the variable being created.
  # @liquid_syntax_keyword value The value you want to assign to the variable.
  class Capture < Block
    include ParserSwitching

    Syntax = /(#{VariableSignature}+)/o

    attr_reader :to

    def initialize(tag_name, markup, options)
      super
      parse_with_selected_parser(markup)
    end

    def lax_parse(markup)
      if markup =~ Syntax
        @to = Regexp.last_match(1)
      else
        raise SyntaxError, options[:locale].t("errors.syntax.capture")
      end
    end

    def strict_parse(markup)
      lax_parse(markup)
    end

    def strict2_parse(markup)
      p = @parse_context.new_parser(markup.strip)
      @to = p.consume(:id)
      p.consume(:end_of_string)
    end

    def render_to_output_buffer(context, output)
      context.resource_limits.with_capture do
        capture_output = render(context)
        context.scopes.last[@to] = capture_output
      end

View on GitHub (pinned to 807d45a6b3)