{"record":{"id":"9f615e60d961dfb6","repo":"Shopify/liquid","slug":"nesting-too-deep","errorCode":null,"errorMessage":"Nesting too deep","messagePattern":"Nesting too deep","errorType":"exception","errorClass":"Liquid::StackLevelError","httpStatus":null,"severity":"error","filePath":"lib/liquid/block.rb","lineNumber":77,"sourceCode":"    def block_name\n      @tag_name\n    end\n\n    def block_delimiter\n      @block_delimiter ||= \"end#{block_name}\"\n    end\n\n    private\n\n    # @api public\n    def new_body\n      parse_context.new_block_body\n    end\n\n    # @api public\n    def parse_body(body, tokens)\n      if parse_context.depth >= MAX_DEPTH\n        raise StackLevelError, \"Nesting too deep\"\n      end\n      parse_context.depth += 1\n      begin\n        body.parse(tokens, parse_context) do |end_tag_name, end_tag_params|\n          @blank &&= body.blank?\n\n          return false if end_tag_name == block_delimiter\n          raise_tag_never_closed(block_name) unless end_tag_name\n\n          # this tag is not registered with the system\n          # pass it to the current block for special handling or error reporting\n          unknown_tag(end_tag_name, end_tag_params, tokens)\n        end\n      ensure\n        parse_context.depth -= 1\n      end\n\n      true","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/Shopify/liquid/blob/807d45a6b3d4568e64e86b375e3702df2c7c860c/lib/liquid/block.rb#L59-L95","documentation":"Liquid raises this StackLevelError (a Liquid::Error subclass, not a SyntaxError) when template nesting depth reaches MAX_DEPTH during parse_body. It guards the recursive block parser against stack exhaustion from deeply or maliciously nested tags, e.g. thousands of nested `{% if %}`s.","triggerScenarios":"Parsing a template with more nested block tags than MAX_DEPTH (e.g. >100 nested ifs/fors); recursive includes/includes that reference each other; adversarial user-supplied templates; generated templates with runaway nesting.","commonSituations":"Accepting user-authored templates (CMS themes, email builders) without depth limits; accidental recursion where a template includes itself; code generators emitting nested conditionals in a loop.","solutions":["Flatten the template logic — combine conditions or restructure to reduce nesting levels.","If templates come from users, sanitize/limit them before parse (length, tag counts, include depth).","If recursion is via `{% include %}`, break the include cycle.","Only raise MAX_DEPTH deliberately and with awareness of Ruby stack limits."],"exampleFix":"// before\n{% if a %}{% if b %}{% if c %}... (100+ levels) ...{% endif %}{% endif %}{% endif %}\n// after\n{% if a and b and c %}\n  content\n{% endif %}","handlingStrategy":"validation","validationCode":"def nesting_depth(src)\n  cur = max = 0\n  src.scan(/{%-?\\s*(\\w+)/).flatten.each do |t|\n    if %w[if for case unless tablerow].include?(t)\n      cur += 1; max = [max, cur].max\n    elsif t.start_with?('end')\n      cur -= 1\n    end\n  end\n  max\nend\nraise 'too deep' if nesting_depth(src) > 50","typeGuard":"null","tryCatchPattern":"begin\n  Liquid::Template.parse(src)\nrescue Liquid::StackLevelError => e\n  logger.warn(\"template nesting too deep: #{e.message}\")\n  nil\nend","preventionTips":["Limit user-supplied template complexity (depth/count limits) before parse.","Combine nested conditions with and/or where possible.","Break the include cycles that cause runaway recursion.","Consider a parse timeout/size cap for untrusted templates."],"tags":["liquid","recursion","stack-depth","parse-error"],"backgroundTag":"value-out-of-range","analyzedSha":"807d45a6b3d4568e64e86b375e3702df2c7c860c","analyzedAt":"2026-09-08T11:31:38.917Z","contentChangedAt":"2026-09-08T11:31:38.917Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}