Shopify/liquid · error · Liquid::SyntaxError
errors.syntax.tag_termination
Error message
errors.syntax.tag_termination (locale: "Tag '{token}' was not properly terminated with regexp: {tag_end}") What it means
Liquid raises this SyntaxError when a `{% ... %}` tag is never closed with the tag-end delimiter (`%}`), detected during block body parsing. raise_missing_tag_terminator is invoked when the scanner reaches EOF (or an unexpected token boundary) while still inside a tag, showing the raw token and the expected terminator regexp.
Solutions
- Add the missing `%}` terminator to the tag shown in the error.
- Check that quotes inside the tag are balanced — an unclosed string can hide the `%}`.
- Verify the file wasn't truncated or mangled by a build/minify step.
- Use an editor with Liquid syntax highlighting to spot unterminated tags early.
Example fix
// before
{% assign title = page.title }
// after
{% assign title = page.title %} Defensive patterns
Strategy: validation
Validate before calling
src.scan(/{%(?!%).*?[^%]\z/) # sanity: ensure every `{%` on a line has a following `%}`
src.each_line { |l| warn "unterminated tag: #{l}" if l.include?('{%') && !l.include?('%}') } Type guard
null
Try / catch
begin
Liquid::Template.parse(src)
rescue Liquid::SyntaxError => e
if e.message.include?('was not properly terminated')
logger.error("unterminated liquid tag: #{e.message}")
fallback_template
else
raise
end
end Prevention
- Use Liquid-aware syntax highlighting to spot missing `%}`.
- Balance quotes inside tags before adding the terminator.
- Beware minifiers/sanitizers that strip `%}`.
- Keep templates in files, not shell-escaped strings, to avoid mangling.
When it happens
Trigger: Writing `{% if x }` or `{% assign y = 1` (missing `%}`); an editor stripping `%}`; unquoted strings containing characters that swallow the terminator like `{% assign x = "a%}" ...` mis-nesting; truncated template files.
Common situations: Hand-writing templates in editors without Liquid syntax highlighting; minifiers or HTML sanitizers mangling `%}`; copy/paste losing characters; templates stored in YAML/JSON where `}` escaping goes wrong.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- errors.syntax.unexpected_else (locale: Unexpected 'else'…
- errors.syntax.invalid_delimiter
- errors.syntax.unknown_tag (locale: 'Unknown tag 'tag'')
- errors.syntax.tag_never_closed
- errors.syntax.variable_termination
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/5e24d893ccae26ad.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/block_body.rb:77
end
new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
@blank &&= new_tag.blank?
@nodelist << new_tag
end
parse_context.line_number = tokenizer.line_number
end
yield nil, nil
end
# @api private
def self.unknown_tag_in_liquid_tag(tag, parse_context)
Block.raise_unknown_tag(tag, 'liquid', '%}', parse_context)
end
# @api private
def self.raise_missing_tag_terminator(token, parse_context)
raise SyntaxError, parse_context.locale.t("errors.syntax.tag_termination", token: token, tag_end: TagEnd.inspect)
end
# @api private
def self.raise_missing_variable_terminator(token, parse_context)
raise SyntaxError, parse_context.locale.t("errors.syntax.variable_termination", token: token, tag_end: VariableEnd.inspect)
end
# @api private
def self.render_node(context, output, node)
node.render_to_output_buffer(context, output)
rescue => exc
blank_tag = !node.instance_of?(Variable) && node.blank?
rescue_render_node(context, output, node.line_number, exc, blank_tag)
end
# @api private
def self.rescue_render_node(context, output, line_number, exc, blank_tag)
case excView on GitHub (pinned to 807d45a6b3)