fix(server): favicon resolution no longer pins the event loop - #5531
fix(server): favicon resolution no longer pins the event loop#5531vbb-it wants to merge 1 commit into
Conversation
`LINK_ICON_OBJ_RE` was unanchored, so it restarted at every offset in an
icon source file and rescanned forward from each one. A project with no
icon file and a large `index.html` that has no `<link rel="icon">` made
favicon resolution spin for minutes on the server's only thread, so every
connection stopped being answered and the desktop client dropped into a
permanent reconnect loop. Measured on a 1.6 MB generated `index.html`:
200 KB already cost ~4s, and the full file never completed.
Anchor the object pattern on the literal `{` and bound each attempt to the
enclosing object, then pull `href` from the matched object. Both key orders
and `shortcut icon` still resolve, and the same 1.6 MB file now finishes in
2 ms. The object branch had no test coverage, so this adds cases for both
key orders plus a large brace-sparse source that hangs without the fix.
Fixes #5530
Model: Claude Opus 5 · Harness: Claude Code
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| /<link\b(?=[^>]*\brel=["'](?:icon|shortcut icon)["'])(?=[^>]*\bhref=["']([^"'?]+))[^>]*>/i; | ||
| const LINK_ICON_OBJ_RE = | ||
| /(?=[^}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'])(?=[^}]*\bhref\s*:\s*["']([^"'?]+))[^}]*/i; | ||
| const LINK_ICON_OBJ_RE = /\{[^{}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'][^{}]*\}/i; |
There was a problem hiding this comment.
🟡 Medium project/ProjectFaviconResolver.ts:62
LINK_ICON_OBJ_RE uses [^{}]* to bound the match, so any icon metadata object containing nested braces fails to match — for example { attributes: {}, rel: "icon", href: "/favicon.svg" } returns null from extractIconHref instead of /favicon.svg. The prior lookahead-based pattern could scan past inner braces; the new anchored pattern cannot. Consider using a pattern that tolerates nested braces, or strip/normalize brace depth before matching.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/project/ProjectFaviconResolver.ts around line 62:
`LINK_ICON_OBJ_RE` uses `[^{}]*` to bound the match, so any icon metadata object containing nested braces fails to match — for example `{ attributes: {}, rel: "icon", href: "/favicon.svg" }` returns `null` from `extractIconHref` instead of `/favicon.svg`. The prior lookahead-based pattern could scan past inner braces; the new anchored pattern cannot. Consider using a pattern that tolerates nested braces, or strip/normalize brace depth before matching.
| /<link\b(?=[^>]*\brel=["'](?:icon|shortcut icon)["'])(?=[^>]*\bhref=["']([^"'?]+))[^>]*>/i; | ||
| const LINK_ICON_OBJ_RE = | ||
| /(?=[^}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'])(?=[^}]*\bhref\s*:\s*["']([^"'?]+))[^}]*/i; | ||
| const LINK_ICON_OBJ_RE = /\{[^{}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'][^{}]*\}/i; |
There was a problem hiding this comment.
🟡 Medium project/ProjectFaviconResolver.ts:62
LINK_ICON_OBJ_RE now matches the first {...} object containing rel: "icon" even when that object has no href, so extractIconHref never examines later valid declarations. A source like [{ rel: "icon" }, { rel: "icon", href: "/favicon.svg" }] returns null instead of /favicon.svg. The old regex required both rel and href in the same candidate. Consider restoring the href lookahead inside LINK_ICON_OBJ_RE so non-href objects are skipped.
| const LINK_ICON_OBJ_RE = /\{[^{}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'][^{}]*\}/i; | |
| const LINK_ICON_OBJ_RE = /\{(?=[^{}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'])(?=[^{}]*\bhref\s*:\s*["']([^"'?]+))[^{}]*\}/i; |
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/project/ProjectFaviconResolver.ts around line 62:
`LINK_ICON_OBJ_RE` now matches the first `{...}` object containing `rel: "icon"` even when that object has no `href`, so `extractIconHref` never examines later valid declarations. A source like `[{ rel: "icon" }, { rel: "icon", href: "/favicon.svg" }]` returns `null` instead of `/favicon.svg`. The old regex required both `rel` and `href` in the same candidate. Consider restoring the `href` lookahead inside `LINK_ICON_OBJ_RE` so non-`href` objects are skipped.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4b77158. Configure here.
| const objMatch = source.match(LINK_ICON_OBJ_RE); | ||
| if (objMatch?.[1]) return objMatch[1]; | ||
| const objHref = objMatch?.[0].match(ICON_HREF_RE); | ||
| if (objHref?.[1]) return objHref[1]; |
There was a problem hiding this comment.
Skips later valid icon objects
Medium Severity
LINK_ICON_OBJ_RE now matches any brace group with rel: "icon" and no longer requires a quoted href in that same object. extractIconHref then only inspects the first match, so if that object has no extractable href (missing, backtick template, or variable), a later valid icon object is never considered and resolution returns null.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 4b77158. Configure here.
ApprovabilityVerdict: Needs human review 2 blocking correctness issues found. Multiple unresolved review comments identify functional regressions where the new regex pattern fails to match valid icon metadata (nested braces, objects without href). These bugs could cause favicon resolution to fail in legitimate cases and should be addressed before merging. You can customize Macroscope's approvability policy. Learn more. |
|
Closing this — it was opened from the wrong account. Superseded by #5538 (issue moved to #5537). The bot findings here were both correct and are fixed in the new PR: anchoring the pattern on |


What Changed
LINK_ICON_OBJ_REinProjectFaviconResolveris now anchored on the literal{and bounded to the enclosing object, withhrefpulled out of the matched object by a second small pattern.Three tests come with it. The object branch had no coverage at all — every existing case exercises the
<link>branch — so this adds both key orders (relfirst,hreffirst withshortcut icon) plus a large brace-sparse source that hangs the suite without the fix.LINK_ICON_HTML_REis untouched. It is already anchored on<link\b, so it was never part of the problem.Why
Fixes #5530.
The old pattern started with a lookahead and no literal anchor, so the engine retried at every offset in the file and rescanned forward with
[^}]*from each one. On a brace-sparse file that is quadratic.That turns one file into a full environment outage. A project with no icon and a large
index.htmllacking<link rel="icon">— the shape of a generated single-file build — maderesolvePathspin for minutes on the server's only thread. Every endpoint stopped answering, including/.well-known/t3/environment; the desktop client timed out at 10s, respawned the server, and it re-scanned and re-wedged. The environment never recovered on its own.Anchoring on
{restricts start positions to real object literals and bounds each attempt to a single brace group, so the work stays proportional to file size.Measured on the 1.6 MB generated
index.htmlthat triggered this:Semantics are preserved —
relbeforehref,hrefbeforerel,shortcut icon, and query-string stripping all still resolve.UI Changes
None.
Verification
vp test run src/project/ProjectFaviconResolver.test.ts— 15 passed (12 existing + 3 new), 415 ms.vp linton both changed files: clean.tsgo --noEmitforapps/server: exit 0, no diagnostics in the changed files.Branched off
main@e4abc31f.Checklist
Model: Claude Opus 5 · Harness: Claude Code
Note
Medium Risk
Touches core server favicon discovery on every workspace resolve; regex change is localized but incorrect matching could miss icons in nested objects with inner braces.
Overview
Fixes catastrophic slowdown in
ProjectFaviconResolverwhen scanning large sources that lack icon metadata (e.g. generated single-fileindex.html), which could block the server event loop for minutes.Object-literal icon detection no longer uses an unanchored lookahead over
[^}]*. It now matches only brace-bounded objects that declarerel: "icon"/"shortcut icon", then readshrefvia a separateICON_HREF_REpass sorel/hreforder stays flexible without rescanning the whole file at every offset.Tests add first coverage for the object-metadata path (route
headlinks andhref-before-rel), plus a large-file timing guard that expectsresolvePathto finish in under 5s when no icon is present.Reviewed by Cursor Bugbot for commit 4b77158. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix favicon resolution in
ProjectFaviconResolverto avoid pinning the event loopLINK_ICON_OBJ_RE) with an anchored brace-delimited pattern, bounding object-metadata scans to a single{...}block.ICON_HREF_REto extracthreffrom the matched object block, supporting any property order.📊 Macroscope summarized 4b77158. 1 file reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.