Which component is affected?
Qwik Runtime
Describe the bug
In Qwik v2 dev SSR, SSRContainer.openElement inlines the
<script id="qwikloader"> tag as soon as the buffered response crosses
30 KB. The check does not consider the current element-frame stack, so
when the threshold is crossed while the writer is inside an open
<svg> (or <math>) subtree, the script is written into that subtree.
The browser then parses it in HTML5 foreign-content mode, where XML
element rules apply inside <svg>/<math>. The qwikloader source
contains substrings like for(let e=0;e<t.length;e++), and the
tokenizer treats <t.length… as the opening of an XML element. The
script element ends up in the SVG namespace and its body is truncated
at the first such pseudo-tag.
Observable symptoms on the client:
<script id="qwikloader">.namespaceURI is
"http://www.w3.org/2000/svg" (not HTML) — so the browser never
executes it as a script.
- Its
textContent.length is ~3788 chars; the original source is
~4900+ — the rest was eaten by the XML tokenizer.
document.documentElement.getAttribute('q:container') stays
"paused" indefinitely.
- No event handlers wire up. No
useVisibleTask$ ever fires (even with
{ strategy: "document-ready" }). No data is fetched. The page
appears interactive (it is SSR-rendered) but is fully inert.
Offending site:
node_modules/@qwik.dev/core/dist/server.mjs (Qwik 2.0.0-beta.35) at
about line 2042:
if (
this.$noScriptHere$ === 0 &&
this.size > 30 * 1024 &&
elementName !== "body"
) {
this.emitQwikLoaderInline();
}
There is no check that walks this.currentElementFrame.parent looking
for an svg / math ancestor before emitting the inline script.
Suggested fix direction: either short-circuit emitQwikLoaderInline
when an SVG/MathML frame is on the stack (deferring the inline emit
until the writer returns to HTML content), or constrain the inline emit
to known-safe insertion points (e.g. only when the element about to be
opened is itself in the HTML namespace).
I'd be happy to send a PR if a maintainer can confirm the approach
(walking the frame chain seems lowest-risk).
Reproduction
https://github.com/46ki75/qwik-v2-svg-qwikloader-bug
Steps to reproduce
pnpm install
pnpm dev
# open http://localhost:5173/
The / page renders a heading that says:
WAITING — if this text is still here a few seconds after the page
loads, qwikloader DID NOT execute (BUG REPRODUCED).
That heading is updated to "RESUMED OK" by a
useVisibleTask$(..., { strategy: "document-ready" }). With the bug
present, that task never fires and the heading stays on "WAITING".
Direct evidence in DevTools
After the page loads, in the console:
const s = document.getElementById("qwikloader");
({
namespaceURI: s.namespaceURI, // → "http://www.w3.org/2000/svg" (BUG)
parentTag: s.parentNode.nodeName, // → "svg"
scriptTextLen: s.textContent.length, // → 3788 (real source is ~4900 chars)
});
document.documentElement.getAttribute("q:container");
// → "paused"
Byte-position scan of the SSR response
total bytes : 321735
<svg> opens at : [2094, 313291] ← second is Qwik's preloader icon
</svg> closes at : [287612, 313794]
qwikloader open at : 30994 ← inside the first <svg>! depth = 1
System Info
System:
OS: Linux 6.6 Ubuntu 24.04.4 LTS (Noble Numbat) (WSL2)
CPU: (16) x64 Intel(R) Core(TM) Ultra 7 255H
Memory: 3.76 GB / 15.31 GB
Shell: 5.2.21 - /bin/bash
Binaries:
Node: 24.15.0
npm: 11.12.1
pnpm: 10.33.0
Browsers:
Chrome: 148.0.7778.167
npmPackages:
@qwik.dev/core: 2.0.0-beta.35 => 2.0.0-beta.35
@qwik.dev/router: 2.0.0-beta.35 => 2.0.0-beta.35
typescript: 5.8 => 5.8.3
undici: * => 8.3.0
vite: 7.3.2 => 7.3.2
Additional Information
This is not a contrived case — it bit a real project where a text input
component had a trailing trash-can SVG icon. Whenever the surrounding
page content was large enough that the 30 KB threshold landed
mid-icon, the entire page silently stopped resuming: no console error,
no network error, just q:container="paused" forever and every
useVisibleTask$ / routeLoader$-driven fetch never running.
It also reproduces for <math> (any HTML5 foreign-content subtree),
not just <svg>.
Which component is affected?
Qwik Runtime
Describe the bug
In Qwik v2 dev SSR,
SSRContainer.openElementinlines the<script id="qwikloader">tag as soon as the buffered response crosses30 KB. The check does not consider the current element-frame stack, so
when the threshold is crossed while the writer is inside an open
<svg>(or<math>) subtree, the script is written into that subtree.The browser then parses it in HTML5 foreign-content mode, where XML
element rules apply inside
<svg>/<math>. The qwikloader sourcecontains substrings like
for(let e=0;e<t.length;e++), and thetokenizer treats
<t.length…as the opening of an XML element. Thescript element ends up in the SVG namespace and its body is truncated
at the first such pseudo-tag.
Observable symptoms on the client:
<script id="qwikloader">.namespaceURIis"http://www.w3.org/2000/svg"(not HTML) — so the browser neverexecutes it as a script.
textContent.lengthis ~3788 chars; the original source is~4900+ — the rest was eaten by the XML tokenizer.
document.documentElement.getAttribute('q:container')stays"paused"indefinitely.useVisibleTask$ever fires (even with{ strategy: "document-ready" }). No data is fetched. The pageappears interactive (it is SSR-rendered) but is fully inert.
Offending site:
node_modules/@qwik.dev/core/dist/server.mjs(Qwik 2.0.0-beta.35) atabout line 2042:
There is no check that walks
this.currentElementFrame.parentlookingfor an
svg/mathancestor before emitting the inline script.Suggested fix direction: either short-circuit
emitQwikLoaderInlinewhen an SVG/MathML frame is on the stack (deferring the inline emit
until the writer returns to HTML content), or constrain the inline emit
to known-safe insertion points (e.g. only when the element about to be
opened is itself in the HTML namespace).
I'd be happy to send a PR if a maintainer can confirm the approach
(walking the frame chain seems lowest-risk).
Reproduction
https://github.com/46ki75/qwik-v2-svg-qwikloader-bug
Steps to reproduce
pnpm install pnpm dev # open http://localhost:5173/The
/page renders a heading that says:That heading is updated to "RESUMED OK" by a
useVisibleTask$(..., { strategy: "document-ready" }). With the bugpresent, that task never fires and the heading stays on "WAITING".
Direct evidence in DevTools
After the page loads, in the console:
Byte-position scan of the SSR response
System Info
System: OS: Linux 6.6 Ubuntu 24.04.4 LTS (Noble Numbat) (WSL2) CPU: (16) x64 Intel(R) Core(TM) Ultra 7 255H Memory: 3.76 GB / 15.31 GB Shell: 5.2.21 - /bin/bash Binaries: Node: 24.15.0 npm: 11.12.1 pnpm: 10.33.0 Browsers: Chrome: 148.0.7778.167 npmPackages: @qwik.dev/core: 2.0.0-beta.35 => 2.0.0-beta.35 @qwik.dev/router: 2.0.0-beta.35 => 2.0.0-beta.35 typescript: 5.8 => 5.8.3 undici: * => 8.3.0 vite: 7.3.2 => 7.3.2Additional Information
This is not a contrived case — it bit a real project where a text input
component had a trailing trash-can SVG icon. Whenever the surrounding
page content was large enough that the 30 KB threshold landed
mid-icon, the entire page silently stopped resuming: no console error,
no network error, just
q:container="paused"forever and everyuseVisibleTask$/routeLoader$-driven fetch never running.It also reproduces for
<math>(any HTML5 foreign-content subtree),not just
<svg>.