Shopify/liquid · error · Liquid::SyntaxError
errors.syntax.unexpected_outer_tag
Error message
errors.syntax.unexpected_outer_tag (locale: "'{tag}' is not allowed outside of if or case blocks") What it means
Document#unknown_tag raises a Liquid::SyntaxError with the localized message 'errors.syntax.unexpected_outer_tag' when an 'else' or 'end' tag is encountered at the document (top) level — i.e. outside any {% if %} or {% case %} block. The document parser has no open block to attach these tags to, so the template is malformed.
Solutions
- Locate the orphaned {% else %}/{% end... %} tag and remove it or restore its matching opening block.
- Recount open/close pairs for each block tag (if/case/for/unless/tablerow) in the template.
- Use a template linter or parse-check templates in CI before deploy.
Example fix
// before
{% endif %}
Hello
// after
{% if condition %}
Hello
{% endif %} Defensive patterns
Strategy: validation
Validate before calling
def balanced_block_tags?(src)
opens = src.scan(/\{%-?\s*(if|unless|case|for)\b/).size
closes = src.scan(/\{%-?\s*end\w+/).size
opens == closes && !src.match?(/\{%-?\s*else/)
end Type guard
def parseable_template?(src) Liquid::Template.parse(src) true rescue Liquid::SyntaxError false end
Try / catch
begin
Liquid::Template.parse(src)
rescue Liquid::SyntaxError => e
notify_author("Orphaned else/end tag: #{e.message}")
end Prevention
- Pair every if/case/for with its end tag; check counts in CI.
- Never concatenate template fragments blindly.
- Use a template linter that detects orphaned else/end tags.
- Back up templates before manual edits.
When it happens
Trigger: Parsing (Template.parse) a template containing a top-level {% else %}, {% endif %}, {% endfor %}, {% endcase %}, etc., with no matching opening if/case block in scope.
Common situations: A stray {% endif %} left after deleting an {% if %}; unbalanced tags after manual edits; template concatenation that mixes fragments; broken split-tag logic in generated templates.
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.tag_termination
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/f48304447d2c09e7.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/document.rb:34
end
def nodelist
@body.nodelist
end
def parse(tokenizer, parse_context)
while parse_body(tokenizer)
end
@body.freeze
rescue SyntaxError => e
e.line_number ||= parse_context.line_number
raise
end
def unknown_tag(tag, _markup, _tokenizer)
case tag
when 'else', 'end'
raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_outer_tag", tag: tag)
else
raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag", tag: tag)
end
end
def render_to_output_buffer(context, output)
@body.render_to_output_buffer(context, output)
end
def render(context)
render_to_output_buffer(context, +'')
end
private
def new_body
parse_context.new_block_body
endView on GitHub (pinned to 807d45a6b3)