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

  1. Add or restore the matching `{% if %}`/`{% case %}`/`{% unless %}` opening tag before the `{% else %}`.
  2. Check nesting so the `{% else %}` belongs to the nearest open block — count opens/closes in the template.
  3. If the else is meant to be standalone output, escape it or remove it.
  4. 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

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


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)
    end

View on GitHub (pinned to 807d45a6b3)