dotnet/aspnetcore · critical
Worker .NET runtime not loaded
Error message
Worker .NET runtime not loaded
What it means
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.
Source
Thrown at src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWebWorker-CSharp/wwwroot/dotnet-web-worker.js:35
} catch (err) {
const errorMessage = err?.message ?? String(err);
startupError = errorMessage;
console.error("[Worker] Failed to initialize .NET:", err);
self.postMessage({ type: "ready", error: errorMessage });
}
}
self.addEventListener('message', async (e) => {
if (e.data.type === 'init') {
await initialize(e.data.dotnetJsUrl, e.data.assemblyName);
return;
}
const { method, args, requestId } = e.data;
try {
if (Object.keys(workerExports).length === 0) {
throw new Error(startupError || "Worker .NET runtime not loaded");
}
const fn = method.split('.').reduce((obj, part) => obj?.[part], workerExports);
if (typeof fn !== 'function') {
throw new Error(`Method not found: ${method}`);
}
const result = await fn(...args);
self.postMessage({ type: "result", requestId, result }, collectTransferables(result));
} catch (err) {
self.postMessage({ type: "result", requestId, error: err?.message ?? String(err) });
}
});
function collectTransferables(value) {
if (ArrayBuffer.isView(value)) return [value.buffer];
if (value instanceof ArrayBuffer) return [value];
return [];View on GitHub (pinned to 294cab2f9b)
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.
Example fix
// before
worker.postMessage({ type:'init', dotnetJsUrl, assemblyName });
worker.postMessage({ method:'DoThing', args:[], requestId:1 }); // race
// after
worker.addEventListener('message', function ready(e){
if (e.data.type==='ready' && !e.data.error) {
worker.removeEventListener('message', ready);
worker.postMessage({ method:'DoThing', args:[], requestId:1 });
}
});
worker.postMessage({ type:'init', dotnetJsUrl, assemblyName }); Defensive patterns
Strategy: validation
Validate before calling
function assertWorkerReady(exports) {
if (!exports || Object.keys(exports).length === 0) throw new Error('Worker not initialized; send init and await ready first.');
} Type guard
function isWorkerReady(e: any): boolean { return e && typeof e === 'object' && Object.keys(e).length > 0; } Try / catch
null
Prevention
- Await the worker's {type:'ready'} before sending invocations.
- Queue calls until ready.
- Verify dotnetJsUrl resolves before init.
When it happens
Trigger: 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').
Common situations: 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.
Related errors
- ' {GetType().Name}' already initialized.
- ' {GetType().Name}' has not been initialized.
- Services cannot be accessed before the component is initiali
- PersistentComponentState already initialized.
- Dynamic root components have not been enabled in this applic
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/6884e303126c7c9e.
Report an issue: GitHub.