{"record":{"id":"d0f4e5e4479a4580","repo":"GraphiteEditor/Graphite","slug":"failed-to-fetch-wasm-binary-part-status-failedr","errorCode":null,"errorMessage":"Failed to fetch Wasm binary part (status ${failedResponse.status}): ${failedResponse.url}","messagePattern":"Failed to fetch Wasm binary part \\(status (.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"frontend/src/utility-functions/wasm-loader.ts","lineNumber":18,"sourceCode":"import init from \"/wrapper/pkg/graphite_wasm_wrapper\";\nimport wasmBinaryUrl from \"/wrapper/pkg/graphite_wasm_wrapper_bg.wasm?url\";\n\n// Initializes the editor's Wasm module, rejoining the parts that CI deployments split the binary into\n// to fit under the single-file size limit (see `wasmSplitting` in `vite.config.ts`)\nexport async function initWasm() {\n\t// Local and native builds keep the binary whole, letting the wasm-bindgen glue code load it directly\n\tif (__WASM_PART_COUNT__ <= 1) return init();\n\n\t// Fetch all parts in parallel (served from the service worker's precache once it is installed)\n\tconst partRequests = [];\n\tfor (let index = 0; index < __WASM_PART_COUNT__; index += 1) {\n\t\tpartRequests.push(fetch(wasmBinaryUrl.replace(/\\.wasm$/, `-part${index}.wasm`)));\n\t}\n\tconst partResponses = await Promise.all(partRequests);\n\n\tconst failedResponse = partResponses.find((response) => !response.ok);\n\tif (failedResponse) throw new Error(`Failed to fetch Wasm binary part (status ${failedResponse.status}): ${failedResponse.url}`);\n\n\t// Rejoin the parts and hand them to wasm-bindgen as a single response, with the MIME type needed for streaming compilation\n\tconst parts = await Promise.all(partResponses.map((response) => response.blob()));\n\tconst joined = new Response(new Blob(parts), { headers: { \"Content-Type\": \"application/wasm\" } });\n\t// eslint-disable-next-line camelcase\n\treturn init({ module_or_path: joined });\n}\n","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/frontend/src/utility-functions/wasm-loader.ts#L1-L26","documentation":"Graphite splits large Wasm binaries into chunks: when the build-time constant __WASM_PART_COUNT__ exceeds 1, initWasm() fetches every -partN.wasm file in parallel and any non-ok response aborts with this error before wasm-bindgen's init() runs. The editor cannot boot without the binary, and the service-worker precache install (which normally guarantees these files) is the usual upstream guarantee being violated.","triggerScenarios":"A part file missing on the server: 404 from a partial deploy; wrong vite base/publicPath so wasmBinaryUrl resolves to the wrong directory; an old service-worker precache referencing part URLs that no longer exist after a redeploy; a dev server that has not emitted the split parts.","commonSituations":"Deploys that upload the main bundle but drop some hashed -partN.wasm files; CDN cache purged mid-deploy; switching between whole-binary and split builds while a stale service worker serves old URLs; hosting under a subpath with a misconfigured base URL.","solutions":["Open the failed URL printed in the error (failedResponse.url) and confirm the status — usually 404 for a missing part","Redeploy the complete build output so every -partN.wasm referenced by the bundle exists on the server","Verify the vite base/publicPath so wasmBinaryUrl points at the directory that actually contains the parts","Hard-reload or unregister the old service worker so the new precache manifest repopulates the part files"],"exampleFix":"// before\nconst partResponses = await Promise.all(partRequests);\nconst failedResponse = partResponses.find((response) => !response.ok);\nif (failedResponse) throw new Error(`Failed to fetch Wasm binary part (status ${failedResponse.status}): ${failedResponse.url}`);\n\n// after: retry each part once before failing boot\nasync function fetchPart(url) {\n\tlet last;\n\tfor (let attempt = 0; attempt < 2; attempt += 1) {\n\t\ttry {\n\t\t\tconst r = await fetch(url);\n\t\t\tif (r.ok) return r;\n\t\t\tlast = r;\n\t\t} catch (e) { last = e; }\n\t}\n\tthrow last;\n}\nconst partResponses = await Promise.all(\n\tArray.from({ length: __WASM_PART_COUNT__ }, (_, index) => fetchPart(wasmBinaryUrl.replace(/\\.wasm$/, `-part${index}.wasm`))),\n);","handlingStrategy":"retry","validationCode":"// Verify all part URLs resolve before booting the editor\nasync function partsAvailable(baseUrl: string, count: number): Promise<boolean> {\n\tconst checks = await Promise.all(\n\t\tArray.from({ length: count }, (_, i) => fetch(baseUrl.replace(/\\.wasm$/, `-part${i}.wasm`), { method: \"HEAD\" })),\n\t);\n\treturn checks.every((r) => r.ok);\n}","typeGuard":null,"tryCatchPattern":"// Catch at boot, log the failed part, and offer a reload (reload re-runs SW install and repopulates the precache)\ntry {\n\tawait initWasm();\n} catch (err) {\n\tconsole.error(err);\n\tshowFatalError(\"Editor failed to load. Reload to retry.\");\n}","preventionTips":["Upload all Wasm parts atomically together with the JS bundle that references them","Keep part files in the service-worker precache manifest so a bad deploy fails install loudly instead of at boot","Version part filenames with content hashes and update every reference in one deploy"],"tags":["wasm","deployment","fetch","startup","vite"],"backgroundTag":"wasm-module-load-failure","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}