{"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/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Web.JS/src/Boot.WebAssembly.Common.ts#L169-L205","documentation":"Thrown by startCore when either the Mono WebAssembly platform failed to load (loadWebAssemblyPlatformIfNotStarted) or platform.start() rejected. The original exception is wrapped and re-thrown so the underlying cause (download failure, runtime panic, out-of-memory, incompatible browser) is preserved in the message.","triggerScenarios":"Network failure downloading _framework/blazor.boot.json, the .wasm binary, or the .dll files; the Mono runtime throwing during initialization; a browser without WebAssembly support or with a Content-Security-Policy that blocks wasm-unsafe-eval; out-of-memory on low-end devices; AOT mismatch between published artifacts.","commonSituations":"Offline or flaky network during app load; aggressive CSP without 'wasm-unsafe-eval'; publishing with trimming/AOT that removes required types; cached stale build artifacts after redeploy; older mobile browsers without full WASM support.","solutions":["Read the wrapped ${ex} in the message to identify the root cause (network status, CSP, runtime error) and address that first.","Verify _framework/blazor.boot.json and all referenced .dll/.wasm files are deployed and reachable (check Network tab for 404/failure).","Loosen Content-Security-Policy to allow 'wasm-unsafe-eval' (and the script/wasm sources) for the app origin.","Clear browser cache / service-worker cache to remove stale build artifacts after a redeploy.","If AOT/trimming is enabled, disable it or add the necessary trim-safe roots to confirm the runtime initializes."],"exampleFix":"// before: unhandled rejection aborts the page\nBlazor.start().catch(e => console.error(e));\n// message: \"Failed to start platform. Reason: TypeError: Failed to fetch dynamically imported module ...wasm\"\n\n// after: surface the underlying cause and retry once\ntry {\n  await Blazor.start();\n} catch (e) {\n  console.error('Platform start failed:', e.message);\n  const cause = e.message.replace('Failed to start platform. Reason: ', '');\n  // inspect `cause`, then e.g. reload after cache-bust\n  if (/Failed to fetch/.test(cause)) location.reload();\n}","handlingStrategy":"try-catch","validationCode":"// Most root causes (network, runtime) can't be pre-validated cheaply.\n// Best-effort pre-flight: probe the boot config and CSP.\nasync function preflightWasm() {\n  const r = await fetch('_framework/blazor.boot.json', { cache: 'no-cache' });\n  if (!r.ok) throw new Error('blazor.boot.json unreachable: ' + r.status);\n  // CSP must allow wasm-unsafe-eval; surface a hint if missing.\n  const csp = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]')?.getAttribute('content') || '';\n  if (csp && !/wasm-unsafe-eval/.test(csp)) {\n    console.warn('CSP may block WebAssembly: add \\'wasm-unsafe-eval\\'.');\n  }\n}","typeGuard":"// Runtime support check before booting.\nfunction browserSupportsWasm(): boolean {\n  return typeof WebAssembly === 'object' && typeof WebAssembly.instantiate === 'function';\n}","tryCatchPattern":"try {\n  await Blazor.start();\n} catch (e) {\n  const msg = (e as Error).message;\n  if (msg.startsWith('Failed to start platform.')) {\n    const cause = msg.replace('Failed to start platform. Reason: ', '');\n    console.error('WASM platform failed:', cause);\n    if (/Failed to fetch|NetworkError|404/.test(cause)) {\n      // bust stale cache and retry once\n      if ('caches' in window) await caches.delete('blazor');\n      location.reload();\n    }\n  } else throw e;\n}","preventionTips":["Always await Blazor.start() inside try/catch and surface the wrapped cause.","Ensure _framework/ artifacts are deployed and reachable (watch for 404s).","Allow 'wasm-unsafe-eval' (and your script/wasm sources) in CSP.","Cache-bust after redeploy to avoid stale .dll/.wasm mismatch.","Smoke-test on the lowest-spec target browser you support."],"tags":["blazor-webassembly","startup","runtime","network","csp"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}