dotnet/aspnetcore · critical · Error
Failed to start platform. Reason
Error message
Failed to start platform. Reason: ${ex} What it means
Thrown in startCore (Boot.WebAssembly.Common) when either platformLoadPromise (downloading/booting the Mono WebAssembly runtime) or platform.start() rejects. The inner exception is captured and re-wrapped to make the failure point explicit. This is a fatal error: the .NET runtime did not come up, so no entry point or initializer can run.
Solutions
- Open the browser DevTools Network tab and inspect the failed request referenced by 'ex' — look for 404, MIME, or compression errors.
- Verify blazor.boot.json and all listed .wasm/.dll files are present and served with correct MIME types (application/wasm for .wasm).
- Clear browser cache / disable aggressive CDN caching to drop a stale boot manifest.
- Confirm Content-Security-Policy allows WebAssembly (add 'wasm-unsafe-eval' to script-src).
- Match the runtime and framework versions: republish and redeploy the entire app together.
- Read the full inner exception ('ex') for the specific platform error before retrying.
Example fix
// before
<script src="_framework/blazor.webassembly.js" autostart="true"></script>
<!-- publish output is missing dotnet.runtime.wasm -> platform.start() rejects -->
// after — ensure correct MIME + caching headers in server config (example: static files)
app.UseStaticFiles(new StaticFileOptions {
ServeUnknownFileTypes = true,
DefaultContentType = "application/wasm"
});
// and CSP: script-src 'self' 'wasm-unsafe-eval'; Defensive patterns
Strategy: try-catch
Validate before calling
// Preflight runtime assets before start.
async function preflightWasmAssets() {
const manifest = await (await fetch('_framework/blazor.boot.json')).json();
for (const res of Object.values(manifest.resources.runtime)) {
// existence checks; MIME handled by server
}
} Try / catch
try {
await Blazor.start();
} catch (e) {
if (/Failed to start platform/.test(e.message)) {
console.error('Platform start failed:', e);
// surface inner reason, check CSP, network, MIME; do not blindly retry
showFatalError(e);
} else throw e;
} Prevention
- Serve .wasm with application/wasm and correct compression headers.
- Whitelist 'wasm-unsafe-eval' in script-src CSP.
- Republish runtime and framework assets together to avoid version skew.
- Invalidate cached blazor.boot.json on deploy.
- Read the wrapped inner exception before retrying.
When it happens
Trigger: Mono runtime files (dotnet.*.wasm, *.dll, blazor.boot.json) fail to download, are the wrong version, are corrupt, or are served with the wrong MIME type; the browser blocks WebAssembly features (e.g. CSP, legacy browser, hardware disabled); a JS initializer throws during platform setup; mismatched runtime and framework versions.
Common situations: Stale cached blazor.boot.json after redeployment; CDN or origin returning 404/HTML for .wasm files; strict Content-Security-Policy without 'wasm-unsafe-eval'; incompatible browser; mismatched .NET runtime version between publish output and server; broken HTTP compression of .br/.gz assets.
Related errors
- Blazor has already started.
- Blazor WebAssembly has already started.
- WebAssembly options have already been configured.
- Blazor has already started.
- Blazor has already started.
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/23cc510be07517cb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Web.JS/src/Boot.WebAssembly.Common.ts:187
};
Blazor._internal.endUpdateRootComponents = (batchId: number) =>
components.onAfterUpdateRootComponents?.(batchId);
Blazor._internal.attachRootComponentToElement = (selector, componentId, rendererId) => {
const element = componentAttacher.resolveRegisteredElement(selector);
if (!element) {
attachRootComponentToElement(selector, componentId, rendererId);
} else {
attachRootComponentToLogicalElement(rendererId, element, componentId, false);
}
};
try {
await platformLoadPromise;
await platform.start();
} catch (ex) {
throw new Error(`Failed to start platform. Reason: ${ex}`);
}
// Start up the application
platform.callEntryPoint();
// At this point .NET has been initialized (and has yielded), we can't await the promise because it will
// only end when the app finishes running
const initializer = getInitializer();
initializer.invokeAfterStartedCallbacks(Blazor);
started = true;
resolve();
}
export function hasStartedWebAssembly(): boolean {
return startPromise !== undefined;
}
export function waitForBootConfigLoaded(): Promise<MonoConfig> {
return bootConfigPromise;View on GitHub (pinned to 3600ca084e)