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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions