jdx/mise · error

Tag parsing loop reached loop limit (%d). Consider either in

Error message

Tag parsing loop reached loop limit (%d). Consider either increasing it or checking HTML-code for syntax errors

What it means

Within the main loop, each tag's attributes are parsed in an inner `TagLoop` that also has a limit guard. When attribute scanning for a tag iterates to the limit, it emits "Tag parsing loop reached loop limit (%d)" and breaks — the tag's attributes are only partially parsed, which almost always indicates malformed attribute markup.

Source

Thrown at crates/vfox/lua/htmlparser.lua:173

		openstart, tpos, name = root._text:find(
			"<" ..        -- an uncaptured starting "<"
			"([%w-]+)" .. -- name = the first word, directly following the "<"
			"[^>]*>",     -- include, but not capture everything up to the next ">"
		tpos)
		dbg("[MainLoop]:#LINE# openstart=%s || tpos=%s || name=%s",str(openstart),str(tpos),str(name))
		-- }}}
		if not name then break end
		-- Some more vars {{{
		index = index + 1
		local tag = ElementNode:new(index, str(name), (node or {}), descend, openstart, tpos)
		node = tag
		local tagloop
		local tagst, apos = tag:gettext(), 1
		-- }}}
		while true do -- TagLoop {{{
			dbg("[TagLoop]:#LINE# tag.name=%s, tagloop=%s",str(tag.name),str(tagloop))
			if tagloop == limit then -- {{{
				err("Tag parsing loop reached loop limit (%d). Consider either increasing it or checking HTML-code for syntax errors", limit)
				break
			end -- }}}
			-- Attrs {{{
			local start, k, eq, quote, v, zsp
			start, apos, k, zsp, eq, zsp, quote = tagst:find(
				"%s+" ..         -- some uncaptured space
				"([^%s=/>]+)" .. -- k = an unspaced string up to an optional "=" or the "/" or ">"
				"([%s]-)"..      -- zero or more spaces
				"(=?)" ..        -- eq = the optional; "=", else ""
				"([%s]-)"..      -- zero or more spaces
				[=[(['"]?)]=],      -- quote = an optional "'" or '"' following the "=", or ""
			apos)
			dbg("[TagLoop]:#LINE# start=%s || apos=%s || k=%s || zsp='%s' || eq='%s', quote=[%s]",str(start),str(apos),str(k),str(zsp),str(eq),str(quote))
			-- }}}
			if not k or k == "/>" or k == ">" then break end
			-- Pattern {{{
			if eq == "=" then
				local pattern = "=([^%s>]*)"

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Fix the HTML's attribute quoting/syntax (close all quotes, escape '<' inside values).
  2. Increase the `limit` if the tag legitimately has an enormous number of attributes.
  3. Sanitize or strip the offending tag region before parsing.
  4. Extract attributes with a stricter regex for the known input format instead of the generic parser.

Example fix

// before
<div data-x="unterminated>...</div>  -- TagLoop hits limit
// after
<div data-x="unterminated">...</div>  -- well-formed attributes parse cleanly
Defensive patterns

Strategy: validation

Validate before calling

-- quick sanity check that quotes inside the payload are balanced
local _, q = html:gsub('"',"")
if q % 2 == 1 then return nil, "unbalanced quotes in HTML" end

Type guard

local function balanced_quotes(s) local _, n = s:gsub('"',""); return n % 2 == 0 end

Prevention

When it happens

Trigger: Parsing a tag whose attribute region confuses the scanner (unterminated quotes, stray '=' or '<' inside attribute values) so the TagLoop keeps advancing until `tagloop == limit`.

Common situations: HTML with unclosed quoted attribute values; script/style bodies containing markup-like text; plugin input mixing code snippets into attribute positions.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/9fb803aa1124e89a. Report an issue: GitHub.