{"record":{"id":"ed0dbdbc46400006","repo":"dotnet/runtime","slug":"webcil-asset-virtualpath-is-missing-payloadsi","errorCode":null,"errorMessage":"Webcil asset '${virtualPath}' is missing payloadSize in the boot config.","messagePattern":"Webcil asset '(.+?)' is missing payloadSize in the boot config\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/native/libs/Common/JavaScript/host/assets.ts","lineNumber":54,"sourceCode":"        }\n\n        const ptr = _ems_.HEAPU32[ptrPtr as any >>> 2];\n        _ems_.HEAPU8.set(bytes, ptr >>> 0);\n\n        _ems_.dotnetLogger.debug(`Registered assembly '${virtualPath}' (shortName: '${shortName}') at ${ptr.toString(16)} length ${bytes.length}`);\n        loadedAssemblies.set(virtualPath, { ptr, length: bytes.length });\n        loadedAssemblies.set(shortName, { ptr, length: bytes.length });\n    } finally {\n        _ems_.stackRestore(sp);\n    }\n}\n\nexport async function instantiateWebcilModule(webcilPromise: Promise<Response>, memory: WebAssembly.Memory, virtualPath: string, tableSize?: number, payloadSize?: number): Promise<void> {\n    // The boot config carries payloadSize for every webcil asset (and tableSize for R2R images), so\n    // the loader never buffers the bytes, parses the data section or calls getWebcilSize. Assets\n    // without a tableSize are plain (Webcil wrapper version 0) images.\n    if (typeof payloadSize !== \"number\" || payloadSize === 0) {\n        throw new Error(`Webcil asset '${virtualPath}' is missing payloadSize in the boot config.`);\n    }\n    const tableEntries = typeof tableSize === \"number\" ? tableSize : 0;\n\n    const res = await checkWebcilResponse(webcilPromise, virtualPath);\n    const payloadPtr = allocWebcilPayload(payloadSize);\n    const imports: WebAssembly.Imports = { webcil: buildWebcilImports(memory, payloadPtr, tableEntries) };\n\n    try {\n        let instance: WebAssembly.Instance;\n        const contentType = res.headers && res.headers.get ? res.headers.get(\"Content-Type\") : undefined;\n        const streamingOk = hasInstantiateStreaming && typeof globalThis.Response === \"function\" && res instanceof globalThis.Response && contentType === \"application/wasm\";\n        if (streamingOk) {\n            const instantiated = await WebAssembly.instantiateStreaming(res, imports);\n            instance = instantiated.instance;\n        } else {\n            const data = await res.arrayBuffer();\n            const instantiated = await WebAssembly.instantiate(data, imports);\n            instance = instantiated.instance;","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/Common/JavaScript/host/assets.ts#L36-L72","documentation":"Thrown by instantiateWebcilModule() (src/native/libs/Common/JavaScript/host/assets.ts:49). The host ABI expects every Webcil-in-Wasm asset to declare its payloadSize in the boot config so the loader can pre-allocate the exact image buffer without parsing the data section. When payloadSize is not a number or is 0, the loader refuses to proceed because it cannot size the allocation.","triggerScenarios":"fetchWebcil() (loader/assets.ts:172) calls instantiateWebcilModule with assetInternal.tableSize and assetInternal.payloadSize read from the boot config. If the asset entry for a .wasm assembly lacks payloadSize (or it is 0/undefined), the guard at line 53 fires.","commonSituations":"Mixing a Webcil-capable runtime with an older publish output that did not emit payloadSize per asset; hand-editing or stripping the boot config; a custom loadBootResourceCallback that drops the payloadSize field when rewriting asset metadata.","solutions":["Re-publish the app with the same SDK/runtime version that ships the loader so the boot config emits payloadSize for every webcil asset.","If a custom loadBootResourceCallback rewrites asset metadata, make sure it forwards payloadSize (and tableSize) verbatim.","Verify the published blazor.boot.json / runtime config contains a numeric payloadSize for each *.wasm assembly entry."],"exampleFix":"// before (custom loader drops payloadSize)\nloadBootResource(type, name, uri) {\n  return { name, url: uri }; // payloadSize lost -> 'missing payloadSize'\n}\n\n// after\nloadBootResource(type, name, uri, hash, behavior, asset) {\n  return { name, url: uri, payloadSize: asset.payloadSize, tableSize: asset.tableSize };\n}","handlingStrategy":"validation","validationCode":"function assertWebcilAssetsHavePayloadSize(resources: any): void {\n  for (const a of resources?.assembly ?? []) {\n    if (a.behavior === 'webcil' && (typeof a.payloadSize !== 'number' || a.payloadSize === 0)) {\n      throw new Error(`Asset ${a.name} is missing payloadSize`);\n    }\n  }\n}","typeGuard":"function isWebcilAsset(a: any): a is { payloadSize: number; tableSize?: number; virtualPath: string } {\n  return a && typeof a.payloadSize === 'number' && a.payloadSize > 0;\n}","tryCatchPattern":null,"preventionTips":["Re-publish with the SDK/runtime version that matches the loader so payloadSize is emitted.","Never strip payloadSize/tableSize when rewriting asset metadata in a custom loader.","Validate the boot config for numeric payloadSize on every webcil entry before bootstrapping."],"tags":["webcil","boot-config","configuration"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}