Shopify/liquid · error · Liquid::SyntaxError
errors.syntax.for_invalid_in
errors.syntax.for_invalid_in
Error message
options[:locale].t("errors.syntax.for_invalid_in") What it means
Raised by strict_parse for {% for %} when the token immediately after the loop variable is not the keyword 'in'. In strict parsing mode Liquid requires the canonical 'for <var> in <collection>' grammar and refuses lax-style shorthand.
Solutions
- Use the exact keyword 'in' between variable and collection: {% for item in collection %}
- Remove quotes or unusual separators around the loop variable
- Audit all for tags when enabling strict mode; use a lint pass to find non-'in' forms
Example fix
// before
{% for item of products %}...{% endfor %}
// after
{% for item in products %}...{% endfor %} Defensive patterns
Strategy: validation
Validate before calling
valid = markup =~ /\A\s*[\w\-\"']+\s+in\s+.+\z/ raise Liquid::SyntaxError, "expected 'for x in y'" unless valid
Type guard
def strict_for_ok?(markup) parts = markup.to_s.strip.split(/\s+/, 3) parts.length >= 3 && parts[1] == 'in' end
Try / catch
begin
Liquid::Template.parse(src, error_mode: :strict)
rescue Liquid::SyntaxError => e
logger.error("Strict-mode for-tag error: #{e.message}")
raise
end Prevention
- Use the literal keyword 'in' — never 'of', ':', or '=>'
- When migrating to strict mode, grep templates for 'for ' tags lacking ' in '
- Keep a template test suite that parses with the same error_mode as production
When it happens
Trigger: Rendering with the strict parser (error_mode: :strict) and a for tag like {% for item products %}, {% for item of products %}, or {% for 'item' in products %} where the second token isn't the id 'in'.
Common situations: Migrating templates from lax to strict error mode (e.g. Shopify theme checks or Rails apps switching error_mode) exposes previously-tolerated typos like 'for x of y'.
Related errors
- errors.syntax.for_invalid_attribute
- errors.syntax.unexpected_outer_tag
- errors.syntax.unknown_tag (locale: 'Unknown tag 'tag'')
- errors.syntax.assign
- errors.syntax.capture
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/736215e9a8034cbe.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/tags/for.rb:93
def lax_parse(markup)
if markup =~ Syntax
@variable_name = Regexp.last_match(1)
collection_name = Regexp.last_match(2)
@reversed = !!Regexp.last_match(3)
@name = "#{@variable_name}-#{collection_name}"
@collection_name = parse_expression(collection_name)
markup.scan(TagAttributes) do |key, value|
set_attribute(key, value)
end
else
raise SyntaxError, options[:locale].t("errors.syntax.for")
end
end
def strict_parse(markup)
p = @parse_context.new_parser(markup)
@variable_name = p.consume(:id)
raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_in") unless p.id?('in')
collection_name = p.expression
@collection_name = parse_expression(collection_name, safe: true)
@name = "#{@variable_name}-#{collection_name}"
@reversed = p.id?('reversed')
while p.look(:comma) || p.look(:id)
p.consume?(:comma)
unless (attribute = p.id?('limit') || p.id?('offset'))
raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_attribute")
end
p.consume(:colon)
set_attribute(attribute, p.expression, safe: true)
end
p.consume(:end_of_string)
end
View on GitHub (pinned to 807d45a6b3)