Repository navigation
[Bug]: theme dev proxy 502s on cookie-heavy storefront responses (undici default 16 KiB maxHeaderSize) #8717
Description
Activity
Update: measured the actual thresholds and mapped every header-size limit in the CLI
Follow-up investigation on
@shopify/[email protected]/ Node v24.15.0 corrects the 16 KiB figure above and adds the floor map.1. The effective response-header cap is not 16 KiB on Node 24
Binary-searched with a synthetic local server (padded
Set-Cookie-shaped headers):Response header block Result 31.8 KB (193 headers) passes 40,313 bytes passes 40,625 bytes fails 40 KiB+ fails The documented undici default is 16,384 bytes, but Node's bundled undici copy drifts from the package docs, and the failing storefront response in this repro exceeds ~40 KB, not merely 16 KiB. The practical point: the CLI's header cap is whatever Node's bundled parser defaults to that week — Node has moved this default before (8 KiB → 16 KiB historically), so the CLI's behavior changes silently with every Node release under it.
2. The CLI authors no header limit of its own
Grepped the entire
dist/bundle: zeromaxHeaderSizein CLI code, zeronew Agent(, zerosetGlobalDispatcher. The onlymaxHeaderSizein the bundle is a vendoredgotlibrary, off the theme-dev proxy path. Every limit on the proxy path is inherited:- CLI → storefront, response headers — undici global fetch default (the limit hit in this issue).
- Browser → CLI, request headers — the dev server is a plain Node
httpserver with its own default request-header cap. The proxy rewrites the storefront'sSet-Cookieonto the127.0.0.1origin, so the browser's localhost cookie jar accumulates Shopify cookies; once the requestCookieheader to127.0.0.1:9292crosses the server-side cap, the proxy dies on the request side instead. Same bug family, other hop — a fix that only raises the undici cap will resurface here. - Proxy-env path — with
HTTPS_PROXY/HTTP_PROXYset, the CLI routes throughhttp-proxy-agent/https-proxy-agent(Node http client parser), same inherited defaults again.
3. Suggested fix, refined
- Pin both caps explicitly in the CLI instead of inheriting Node's drifting defaults: an undici
Agent({ maxHeaderSize })(or equivalent) for the upstream fetch andserver.maxHeaderSizeon the local dev server. - 128 KiB is the defensible number: it matches the largest mainstream CDN ceiling (Cloudflare raised its total header limit to 128 KB in Oct 2025), covers the measured failing case with ~3x headroom, and llhttp's cap is an upper-bound check, not a preallocated buffer — there is no offsetting cost.
- Surface
error.cause.codein the 502 error page; it took aNODE_OPTIONSfetch shim to findUND_ERR_HEADERS_OVERFLOWunder the wrappedTypeError: fetch failed.
(
--max-http-header-sizeviaNODE_OPTIONSwas also tested as a possible workaround: it does not raise the bundled undici fetch's cap on Node 24.15.0 — 96 KB and 128 KB header blocks still failed with the flag set.)Follow-up: the fix is version-proof if it uses the explicit option, not the flag
Checked against the CLI's supported Node range and the Node/undici option history:
@shopify/[email protected]declaresengines: { node: ">=22.12.0" }— every Node version the CLI supports has both relevant options.http.createServer({ maxHeaderSize })— supported since Node v13.3.0 (per the v22 LTS docs). Covers the browser→CLI hop on every supported version.- undici
Agent({ maxHeaderSize })— the option predates every undici copy Node 22/23/24 bundle. Covers the CLI→storefront hop.
An explicit value replaces each version's default, so behavior becomes one number on every supported and future Node release — which matters because the default demonstrably drifts: Node 22 docs say 16 KiB, this repro's Node 24.15.0 measured ~40 KB effective, older Node documented 8 KiB.
One asymmetry for whoever picks this up: the
--max-http-header-sizeflag is not the version-proof route. It did not raise the bundled undici fetch's cap on Node 24.15.0 in testing (96 KB and 128 KB header blocks still failed with the flag set), even though the standalone undici package documents reading that flag. Fixing this by launching a process with the flag instead of passing the option in code just trades one drifting default for another. The durable fix is the explicit option, on both hops.
[Bug]:
theme devproxy 502s on cookie-heavy storefront responses (undici default 16 KiBmaxHeaderSize)Description
shopify theme devrenders all pages as 502 ("Failed to render storefront") once the browser has cookies for the store. The storefront proxy dies parsing the upstream response headers: the response to a cookie'd request carries enoughSet-Cookieheaders to exceed undici's default 16 KiB header limit. The undici error (UND_ERR_HEADERS_OVERFLOW) is swallowed and surfaced as a bareTypeError: fetch failed→ 502.The theme, the dev theme, and the store are all fine — a cookie-less request to the same URL renders correctly.
Steps to reproduce
shopify theme pull --liveandshopify theme devon any store whose storefront sets a largeSet-Cookiecollection on cookie'd requests (this merchant: a Plus cosmetics store with cart/localization/tracking cookies).http://127.0.0.1:9292/in a browser with an existing cookie jar for the store.curlto the same URL renders. Nodefetchfrom a fresh process renders. Only the CLI's cookie-forwarding proxy path fails.Isolating the real error
The CLI wraps the undici error and drops
error.cause. Attaching this shim viaNODE_OPTIONS="--require /tmp/shim.cjs"and re-runningtheme devreveals the cause:Output:
Supporting measurements
GET https://REDACTED-store.myshopify.com/?_fd=0&pb=0(with the CLI'sUser-Agent): 200, full 940 KB body, response header block ≈ 7.9 KB — under the 16 KiB cap, no failure.Set-Cookiecollection, pushing the response header block past 16 KiB →UND_ERR_HEADERS_OVERFLOW.replace_templatesform bodies, up to 2 MB) both succeed without cookies, so neither method, body, nor header shape is the trigger — only response header size.Suggested fix
Agentwith a largermaxHeaderSize(e.g. 64–128 KiB) instead of undici's 16 KiB default. Shopify storefronts legitimately set largeSet-Cookiecollections on cookie'd requests.error.cause.code(e.g.UND_ERR_HEADERS_OVERFLOW) instead of only the wrappedTypeError: fetch failedstack — it took aNODE_OPTIONSshim to find the actual cause.Workaround
Use an incognito/private window for
http://127.0.0.1:9292/, or clear site data for127.0.0.1and the store domain.Environment
@shopify/[email protected](pnpm global)Possibly related: #8480 (
theme devproxy 502, cause not isolated — same proxy path, this report's cause code may explain it) and #3963.