Shopify/liquid · error · Liquid::SyntaxError
errors.syntax.unexpected_else (locale: Unexpected 'else'…
Error message
errors.syntax.unexpected_else (locale: Unexpected 'else' without matching if/case tag in 'block_name')
What it means
Liquid raises this SyntaxError when an `{% else %}` (or `{% elsif %}`) tag appears without an open `{% if %}`, `{% case %}`, or `{% unless %}` block to match. Block.raise_unknown_tag intercepts every `else`-family unknown tag and reports which block type the parser was inside (block_name), so a stray else fails at parse time rather than silently rendering.
Solutions
- Add or restore the matching `{% if %}`/`{% case %}`/`{% unless %}` opening tag before the `{% else %}`.
- Check nesting so the `{% else %}` belongs to the nearest open block — count opens/closes in the template.
- If the else is meant to be standalone output, escape it or remove it.
- For custom block tags, register 'else' in the tag markup or pass the correct block_delimiter so parse accepts it.
Example fix
// before
{% else %}
fallback
{% endif %}
// after
{% if available %}
content
{% else %}
fallback
{% endif %} Defensive patterns
Strategy: validation
Validate before calling
def else_balanced?(src)
opens = src.scan(/{%-?\s*(if|case|unless)\b/).size
elses = src.scan(/{%-?\s*(else|elsif)\b/).size
closes = src.scan(/{%-?\s*end(if|case|unless)?\b/).size
opens >= 1 && elses <= opens
end Type guard
null
Try / catch
begin
Liquid::Template.parse(src)
rescue Liquid::SyntaxError => e
logger.warn("liquid syntax: #{e.message}")
fallback_template
end Prevention
- Always write the if/else/endif skeleton first, then fill in branches.
- Use an editor with Liquid syntax highlighting and bracket matching.
- Parse templates in CI before deploying.
- Avoid copy-pasting partial branches without their opening block.
When it happens
Trigger: Writing `{% else %}` in a template with no enclosing if/case/unless; nesting blocks so an else pairs with the wrong open block; using `{% else %}` inside a custom block tag that does not declare an else delimiter; typos that unclosed the real if (e.g. `{% ify %}`).
Common situations: Copy-pasting template fragments out of context; refactoring that removes or renames an `{% if %}` while keeping its `{% else %}`; custom tag authors passing the wrong block_name/delimiter to parse_body; templates split across includes where the if lives in the parent.
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.invalid_delimiter
- errors.syntax.unknown_tag (locale: 'Unknown tag 'tag'')
- errors.syntax.tag_never_closed
- errors.syntax.tag_termination
- errors.syntax.variable_termination
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/2c837633fa0de879.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/block.rb:39
@body.render(context)
end
def blank?
@blank
end
def nodelist
@body.nodelist
end
def unknown_tag(tag_name, _markup, _tokenizer)
Block.raise_unknown_tag(tag_name, block_name, block_delimiter, parse_context)
end
# @api private
def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context)
if tag == 'else'
raise SyntaxError, parse_context.locale.t(
"errors.syntax.unexpected_else",
block_name: block_name,
)
elsif tag.start_with?('end')
raise SyntaxError, parse_context.locale.t(
"errors.syntax.invalid_delimiter",
tag: tag,
block_name: block_name,
block_delimiter: block_delimiter,
)
else
raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag", tag: tag)
end
end
def raise_tag_never_closed(block_name)
raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed", block_name: block_name)
endView on GitHub (pinned to 807d45a6b3)