Skip to content

Bug: {% liquid liquid %} raises raw NoMethodError when line numbers are disabled #2101

Description

@Nuhiat-Arefin

Version

  • liquid 5.12.0
  • Ruby 4.0.5
  • Default parse options, where line_numbers is not enabled

Steps to reproduce

require "liquid"

Liquid::Template.parse("{% liquid liquid %}")

Actual behavior

Parsing raises a raw NoMethodError:

NoMethodError: undefined method '-' for nil
  .../liquid-5.12.0/lib/liquid/block_body.rb:51:in `Liquid::BlockBody#parse_for_liquid_tag'

This happens in both :strict and :lax error modes.

Because the exception is not a Liquid::Error, application code that wraps parsing with rescue Liquid::Error will not catch it.

Expected behavior

The template should parse without crashing and render as an empty string.

This is already what happens when line numbers are enabled:

Liquid::Template.parse("{% liquid liquid %}", line_numbers: true).render!
# => ""

For comparison, the same template is accepted as a no-op by other major Liquid implementations:

  • LiquidJS 10.27.0 renders ""
  • python-liquid 2.2.1 renders ""

Root cause

The crash appears to come from lib/liquid/block_body.rb in parse_for_liquid_tag:

if tag_name == 'liquid'
  parse_context.line_number -= 1
  next parse_liquid_tag(markup, parse_context)
end

When line numbers are not tracked, parse_context.line_number is nil. A nested {% liquid %} line therefore executes:

nil -= 1

which raises:

NoMethodError: undefined method '-' for nil

The nearby document-level parsing path already guards this kind of line number adjustment:

if parse_context.line_number
  ...
end

So the issue appears to be an asymmetry between the document-level path and the nested liquid tag path.

Trigger condition

This appears specific to a nested liquid line inside a {% liquid %} tag.

These controls do not trigger the same crash:

Liquid::Template.parse("{% liquid echo 1 %}")
Liquid::Template.parse("{% liquid %}")
Liquid::Template.parse("{% liquid render %}")

The render case fails cleanly as a Liquid parse error rather than escaping as a raw NoMethodError.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions