dotnet/aspnetcore · error · Error
Blazor has already started.
Error message
Blazor has already started.
What it means
Thrown by the local boot() in Boot.WebAssembly.ts (the blazor.webassembly.js entry) when its module-level 'started' flag is already true. The WebAssembly boot entry is single-shot: it normalizes options, configures them, discovers components, and starts the platform.
Source
Thrown at src/Components/Web.JS/src/Boot.WebAssembly.ts:21
/* eslint-disable array-element-newline */
import { Blazor } from './GlobalExports';
import { shouldAutoStart } from './BootCommon';
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
import { setWebAssemblyOptions, startWebAssembly } from './Boot.WebAssembly.Common';
import { WebAssemblyComponentDescriptor, discoverComponents, discoverWebAssemblyOptions } from './Services/ComponentDescriptorDiscovery';
import { DotNet } from '@microsoft/dotnet-js-interop';
import { InitialRootComponentsList } from './Services/InitialRootComponentsList';
import { JSEventRegistry } from './Services/JSEventRegistry';
import { printErr } from './Platform/Mono/MonoPlatform';
type BlazorWebAssemblyStartOptions = Partial<WebAssemblyStartOptions> & { webAssembly?: Partial<WebAssemblyStartOptions> };
let started = false;
async function boot(options?: BlazorWebAssemblyStartOptions): Promise<void> {
if (started) {
throw new Error('Blazor has already started.');
}
started = true;
// Accept the `webAssembly` property from the blazor.web.js options format
const normalizedOptions = options?.webAssembly ?? options ?? {};
setWebAssemblyOptions(Promise.resolve(normalizedOptions));
JSEventRegistry.create(Blazor);
const webAssemblyComponents = discoverComponents(document, 'webassembly') as WebAssemblyComponentDescriptor[];
const webAssemblyOptions = discoverWebAssemblyOptions(document);
const components = new InitialRootComponentsList(webAssemblyComponents);
await startWebAssembly(components, webAssemblyOptions);
}
Blazor.start = boot;
window['DotNet'] = DotNet;
View on GitHub (pinned to 294cab2f9b)
Solutions
- Call Blazor.start() exactly once; remove autostart or the manual call so only one path runs.
- Guard with a window-level flag before invoking.
- Ensure the bundle is loaded once per page load and not re-imported.
Example fix
// before <script src="blazor.webassembly.js" autostart></script> <script>Blazor.start();</script> <!-- throws --> // after <script src="blazor.webassembly.js"></script> <script>Blazor.start();</script>
Defensive patterns
Strategy: validation
Validate before calling
function startWasmBlazorOnce(opts?: any) {
if ((window as any).__blazorWasmStarted) return Promise.resolve();
(window as any).__blazorWasmStarted = true;
return Blazor.start(opts);
} Type guard
function wasmBlazorStarted(): boolean {
return !!(window as any).__blazorWasmStarted;
} Try / catch
try {
await Blazor.start(opts);
} catch (e) {
if (/already started/.test((e as Error).message)) return;
throw e;
} Prevention
- Use autostart OR one manual start; not both.
- Load blazor.webassembly.js once per page load.
- Guard the manual start with a window flag.
- Bust the service-worker cache on redeploy to avoid double-bundle scenarios.
When it happens
Trigger: Calling Blazor.start() a second time on a WebAssembly app, or autostart firing alongside a manual start.
Common situations: Page includes <script src="blazor.webassembly.js" autostart> plus a manual Blazor.start(); HMR reloading the module; an iframe re-running the bundle; PWA service-worker serving a stale copy alongside the new one.
Related errors
- Blazor WebAssembly has already started.
- Blazor has already started.
- Blazor has already started.
- WebAssembly options have already been configured.
- Blazor has already started.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/fa9045b98534142b.
Report an issue: GitHub.