{"record":{"id":"23cc510be07517cb","repo":"dotnet/aspnetcore","slug":"failed-to-start-platform-reason-ex","errorCode":null,"errorMessage":"Failed to start platform. Reason: ${ex}","messagePattern":"Failed to start platform\\. Reason: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/Components/Web.JS/src/Boot.WebAssembly.Common.ts","lineNumber":187,"sourceCode":"  };\n\n  Blazor._internal.endUpdateRootComponents = (batchId: number) =>\n    components.onAfterUpdateRootComponents?.(batchId);\n\n  Blazor._internal.attachRootComponentToElement = (selector, componentId, rendererId) => {\n    const element = componentAttacher.resolveRegisteredElement(selector);\n    if (!element) {\n      attachRootComponentToElement(selector, componentId, rendererId);\n    } else {\n      attachRootComponentToLogicalElement(rendererId, element, componentId, false);\n    }\n  };\n\n  try {\n    await platformLoadPromise;\n    await platform.start();\n  } catch (ex) {\n    throw new Error(`Failed to start platform. Reason: ${ex}`);\n  }\n\n  // Start up the application\n  platform.callEntryPoint();\n  // At this point .NET has been initialized (and has yielded), we can't await the promise because it will\n  // only end when the app finishes running\n  const initializer = getInitializer();\n  initializer.invokeAfterStartedCallbacks(Blazor);\n  started = true;\n  resolve();\n}\n\nexport function hasStartedWebAssembly(): boolean {\n  return startPromise !== undefined;\n}\n\nexport function waitForBootConfigLoaded(): Promise<MonoConfig> {\n  return bootConfigPromise;","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Web.JS/src/Boot.WebAssembly.Common.ts#L169-L205","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n<script src=\"_framework/blazor.webassembly.js\" autostart=\"true\"></script>\n<!-- publish output is missing dotnet.runtime.wasm -> platform.start() rejects -->\n\n// after — ensure correct MIME + caching headers in server config (example: static files)\napp.UseStaticFiles(new StaticFileOptions {\n  ServeUnknownFileTypes = true,\n  DefaultContentType = \"application/wasm\"\n});\n// and CSP: script-src 'self' 'wasm-unsafe-eval';","handlingStrategy":"try-catch","validationCode":"// Preflight runtime assets before start.\nasync function preflightWasmAssets() {\n  const manifest = await (await fetch('_framework/blazor.boot.json')).json();\n  for (const res of Object.values(manifest.resources.runtime)) {\n    // existence checks; MIME handled by server\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Blazor.start();\n} catch (e) {\n  if (/Failed to start platform/.test(e.message)) {\n    console.error('Platform start failed:', e);\n    // surface inner reason, check CSP, network, MIME; do not blindly retry\n    showFatalError(e);\n  } else throw e;\n}","preventionTips":["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."],"tags":["blazor-webassembly","mono-runtime","boot","network","csp"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}