Debugging Qwik Symbol Not Found Errors
A resumable page carries references to code that has not been downloaded yet, and a symbol resolution failure is what happens when one of those references cannot be honoured. The error surfaces at the first interaction a visitor makes, long after the page looked fine, which makes it feel mysterious. It has four causes, all of them deployment-shaped, and all of them cheap to distinguish. The underlying model is in Qwik resumable architecture.
Prerequisites
Diagnostic Steps
Step 1 β Capture the symbol and the URL it resolved to
// Log the failure with everything needed to reproduce it, at the point it happens.
window.addEventListener('qerror', (event) => {
reportError('qwik-symbol', {
message: String(event.detail?.error || event.detail),
// The element attribute carries chunk#symbol β both halves matter.
ref: document.activeElement?.getAttribute('on:click') || 'unknown',
buildId: document.documentElement.dataset.buildId, // stamp every document
url: location.pathname,
});
});
Stamping the document with a build identifier is the single most useful preparation for this class of bug: it turns βsome visitors see errorsβ into βvisitors holding build 4f2a see errorsβ, which names the deploy immediately.
Step 2 β Ask the network what exists
# Does the chunk exist at the URL the document expects?
curl -sI https://example.test/build/q-a91f3c2b.js | head -1
# 404 β the file is gone or the prefix is wrong
# 200 β fetch it and look for the symbol
curl -s https://example.test/build/q-a91f3c2b.js | grep -c 's_8Kd2Lp'
Step 3 β Compare the documentβs build against the deployed manifest
If the document was rendered by one build and the manifest served by another, symbols will reference chunks the manifest does not describe. This happens most often when the server and the static assets deploy independently β a rolling update where one instance is new and another is old will produce it intermittently, affecting a fraction of requests that changes as the rollout proceeds.
Step 4 β Fix the ordering and the retention
Publish chunks first, switch the document second, and keep previous chunks for a grace period. Because the filenames are content-hashed, retaining them costs storage and nothing else. This ordering is the same one described in edge caching and delivery for islands, and it prevents the largest share of these reports outright.
Verification
After changing the deploy process, verify it deliberately rather than waiting for the next incident. Deploy twice in quick succession while holding a page open from the first deploy, then interact with it. Every symbol must resolve, which proves the retention window is real. Then check the error rate for the symbol class over the following day; it should fall to zero rather than to a low number, because the remaining causes are all deployment-shaped and none of them is probabilistic.
Add one permanent guard: a smoke test that loads a page, waits for it to settle, and then triggers an interaction on each interactive element. Because resumability defers code loading until interaction, an ordinary page-load smoke test will not catch a broken symbol reference β only interacting does.
Why Resumability Makes Deploys Sharper
Every architecture that defers code loading has this property, and resumability has it most acutely: the document is a promise about code that will be requested later, so the deploy that changes the code has to honour promises made by earlier deploys.
A traditional bundle avoids the issue by loading everything up front β by the time a deploy happens, the visitor already holds all the code they will need. An islands page is somewhere in between, because a deferred island fetched after a deploy has the same problem for that one chunk. Resumability turns the exception into the rule: nearly every interaction resolves a reference, so nearly every interaction is exposed to a deploy that removed the target.
The practical consequences are worth stating plainly. Asset retention becomes a correctness requirement rather than a nicety. Deploy ordering matters. Rolling updates need the document and asset layers to move together or to tolerate each other. And error reporting needs a build stamp on every document, because without it the reports are unattributable. None of this is difficult, and all of it is invisible until the first deploy that deletes chunks while people are using the site.
Troubleshooting
Why does this only happen after a deploy?
Because a resumable document carries references to specific code chunks by name, and those names change when the code changes. A visitor holding a page from the previous deploy still has the old names in their HTML; if the deploy removed those files, the first interaction after the deploy fails. Nothing is wrong with the code β the document and the assets simply came from different builds.
Should old chunks be deleted on deploy?
Not immediately. Keep them for at least as long as a visitor might plausibly hold a page open β a few hours is a common choice, a day is safer. Because the filenames are content-hashed, old and new coexist without conflict, and the storage cost is trivial next to the failure it prevents. Deleting them at deploy time converts every open tab into a broken page.
How do I tell a stale manifest from a bad base path?
Request the failing chunk URL directly. If it 404s and the same file exists under a different prefix, the base path is wrong. If it 404s and the file does not exist under any prefix, the chunk was removed by a deploy. If it returns 200 but the symbol is still not found, the manifest and the document disagree about which chunk contains that symbol, which is the stale-manifest case.
Related
- Reducing Qwik Serialization Payload Size β the other half of what the document carries.
- Qwik Resumable Architecture β how symbols and chunks are produced in the first place.
- Edge Caching and Delivery for Islands β asset lifetimes, manifests and the deploy ordering that keeps them consistent.
β Back to Qwik Resumable Architecture