{"record":{"id":"6884e303126c7c9e","repo":"dotnet/aspnetcore","slug":"worker-net-runtime-not-loaded","errorCode":null,"errorMessage":"Worker .NET runtime not loaded","messagePattern":"Worker \\.NET runtime not loaded","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWebWorker-CSharp/wwwroot/dotnet-web-worker.js","lineNumber":35,"sourceCode":"    } catch (err) {\n        const errorMessage = err?.message ?? String(err);\n        startupError = errorMessage;\n        console.error(\"[Worker] Failed to initialize .NET:\", err);\n        self.postMessage({ type: \"ready\", error: errorMessage });\n    }\n}\n\nself.addEventListener('message', async (e) => {\n    if (e.data.type === 'init') {\n        await initialize(e.data.dotnetJsUrl, e.data.assemblyName);\n        return;\n    }\n\n    const { method, args, requestId } = e.data;\n\n    try {\n        if (Object.keys(workerExports).length === 0) {\n            throw new Error(startupError || \"Worker .NET runtime not loaded\");\n        }\n\n        const fn = method.split('.').reduce((obj, part) => obj?.[part], workerExports);\n        if (typeof fn !== 'function') {\n            throw new Error(`Method not found: ${method}`);\n        }\n\n        const result = await fn(...args);\n        self.postMessage({ type: \"result\", requestId, result }, collectTransferables(result));\n    } catch (err) {\n        self.postMessage({ type: \"result\", requestId, error: err?.message ?? String(err) });\n    }\n});\n\nfunction collectTransferables(value) {\n    if (ArrayBuffer.isView(value)) return [value.buffer];\n    if (value instanceof ArrayBuffer) return [value];\n    return [];","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWebWorker-CSharp/wwwroot/dotnet-web-worker.js#L17-L53","documentation":"Thrown by the web-worker message handler when workerExports is empty AND there is no captured startupError. workerExports is only populated by initialize() after the .NET runtime boots; if no successful 'init' message has been processed (or it is still in flight), the worker has no callable exports and rejects with this generic message.","triggerScenarios":"Posting a method-invocation message to the worker before posting the 'init' message; the init message failed with an empty error message (err.message undefined); a race where init is asynchronous and the caller dispatches immediately after postMessage('init').","commonSituations":"Caller forgetting the init handshake; race between posting init and the first call; the dotnetJsUrl is wrong so import() rejects but the error message is empty; worker loaded from a cold cache where getAssemblyExports returns nothing.","solutions":["Always send {type:'init', dotnetJsUrl, assemblyName} first and await the worker's {type:'ready'} reply before invoking methods.","If ready includes an error, surface it and do not call further; re-init after fixing the URL.","Verify dotnetJsUrl resolves under the worker's origin and CORS/service-worker allow it.","Queue calls until ready rather than firing immediately."],"exampleFix":"// before\nworker.postMessage({ type:'init', dotnetJsUrl, assemblyName });\nworker.postMessage({ method:'DoThing', args:[], requestId:1 }); // race\n\n// after\nworker.addEventListener('message', function ready(e){\n  if (e.data.type==='ready' && !e.data.error) {\n    worker.removeEventListener('message', ready);\n    worker.postMessage({ method:'DoThing', args:[], requestId:1 });\n  }\n});\nworker.postMessage({ type:'init', dotnetJsUrl, assemblyName });","handlingStrategy":"validation","validationCode":"function assertWorkerReady(exports) {\n  if (!exports || Object.keys(exports).length === 0) throw new Error('Worker not initialized; send init and await ready first.');\n}","typeGuard":"function isWorkerReady(e: any): boolean { return e && typeof e === 'object' && Object.keys(e).length > 0; }","tryCatchPattern":"null","preventionTips":["Await the worker's {type:'ready'} before sending invocations.","Queue calls until ready.","Verify dotnetJsUrl resolves before init."],"tags":["blazor","web-worker","initialization","lifecycle","race"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}