dotnet/aspnetcore · error · Error
Blazor has already started.
Error message
Blazor has already started.
What it means
Thrown by boot() in Boot.Web.ts when the module-level 'started' flag is already true. Boot.Web.ts is the unified web boot (used by Blazor Web App / blazor.web.js) and must initialize the framework exactly once; a second call would re-create the root component manager and re-run initializers.
Solutions
- Invoke Blazor.start() exactly once; rely on autostart OR a single manual call, not both.
- Memoize the boot promise at the call site so subsequent attempts reuse it.
- Disable autostart when you need programmatic control of timing.
- Verify your bundler is not duplicating the boot module under HMR.
Example fix
// before
if (needsBoot) Blazor.start({ ... }); // called on every navigation -> throws
// after
let booted;
async function ensureBoot(opts) {
if (!booted) booted = Blazor.start(opts);
return booted;
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure the unified Web boot runs once.
let webBootPromise;
function bootWebOnce(opts) {
return webBootPromise ?? (webBootPromise = Blazor.start(opts));
} Try / catch
try {
await Blazor.start(opts);
} catch (e) {
if (/already started/.test(e.message)) return;
throw e;
} Prevention
- Disable autostart when starting manually.
- Centralize boot in the application shell, not in pages.
- Guard re-boot attempts in retry/recovery flows.
- Verify the boot script is included once in index.html/_Host.
When it happens
Trigger: Calling Blazor.start() in a Blazor Web App more than once per page load, including via enhanced-navigation or shell code that re-invokes boot.
Common situations: Autostart combined with a manual Blazor.start(); a multi-page shell re-running boot on client-side navigation; bundler/HMR re-evaluation of Boot.Web.ts; retry logic that calls boot again after a transient failure that actually succeeded.
Related errors
- Blazor has already started.
- Blazor has already started.
- Blazor has already started.
- Blazor Server has already started.
- Blazor WebAssembly has already started.
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/0aac84c8dffcef1a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Web.JS/src/Boot.Web.ts:39
import { hasProgrammaticEnhancedNavigationHandler, performProgrammaticEnhancedNavigation } from './Services/NavigationUtils';
import { attachComponentDescriptorHandler, registerAllComponentDescriptors } from './Rendering/DomMerging/DomSync';
import { discoverBrowserConfiguration } from './Services/ComponentDescriptorDiscovery';
import { JSEventRegistry } from './Services/JSEventRegistry';
import { fetchAndInvokeInitializers } from './JSInitializers/JSInitializers.Web';
import { ConsoleLogger } from './Platform/Logging/Loggers';
import { LogLevel } from './Platform/Logging/Logger';
import { resolveOptions, CircuitStartOptions, ReconnectionOptions } from './Platform/Circuits/CircuitStartOptions';
import { JSInitializer } from './JSInitializers/JSInitializers';
import { enableFocusOnNavigate } from './Rendering/FocusOnNavigate';
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
import { createBlazorValidation, ensureNovalidateOnForms } from './Validation';
let started = false;
let rootComponentManager: WebRootComponentManager;
function boot(options?: Partial<WebStartOptions>) : Promise<void> {
if (started) {
throw new Error('Blazor has already started.');
}
started = true;
options = options || {};
options.logLevel ??= LogLevel.Error;
Blazor._internal.isBlazorWeb = true;
// Defined here to avoid inadvertently imported enhanced navigation
// related APIs in WebAssembly or Blazor Server contexts.
Blazor._internal.hotReloadApplied = () => {
if (hasProgrammaticEnhancedNavigationHandler()) {
performProgrammaticEnhancedNavigation(location.href, true);
}
};
const jsEventRegistry = JSEventRegistry.create(Blazor);
rootComponentManager = new WebRootComponentManager(options?.ssr?.circuitInactivityTimeoutMs ?? 2000, jsEventRegistry);
View on GitHub (pinned to 3600ca084e)