dotnet/runtime · error · Error
Loader configuration error: 'mainAssemblyName' is required.
Error message
Loader configuration error: 'mainAssemblyName' is required.
What it means
validateLoaderConfig() throws when loaderConfig.mainAssemblyName is falsy. The main assembly is the entry point the runtime executes via runMain(name, args); without it the loader cannot boot the CLR application. This is a hard precondition — every runtime startup path (create, runMain, runMainAndExit, download) calls validateLoaderConfig first.
Solutions
- Call builder.withMainAssembly('MyApp.dll') before create()/runMain().
- Or pass mainAssemblyName inside withConfig({ mainAssemblyName: 'MyApp.dll', resources: {...} }).
- If using the generated dotnet.boot.config.json, ensure the build produced it; check the <WasmMainAssemblyPath> MSBuild property.
- Confirm the assembly exists in resources.assembly or resources.coreAssembly too (else error 107 follows).
Example fix
// before
const runtime = await dotnet.create();
// after
const runtime = await dotnet
.withMainAssembly('MyApp.dll')
.create(); Defensive patterns
Strategy: validation
Validate before calling
function hasMainAssembly(cfg: any): cfg is { mainAssemblyName: string } {
return typeof cfg?.mainAssemblyName === 'string' && cfg.mainAssemblyName.length > 0;
}
if (!hasMainAssembly(myConfig)) throw new Error('mainAssemblyName missing'); Type guard
function isLoaderConfigWithMain(c: unknown): c is { mainAssemblyName: string } {
return !!c && typeof c === 'object' && typeof (c as any).mainAssemblyName === 'string';
} Try / catch
try { await dotnet.create(); } catch (e) {
if (/mainAssemblyName.*required/.test((e as Error).message)) {
dotnet.withMainAssembly('MyApp.dll');
// retry
} else throw e;
} Prevention
- Always load the MSBuild-generated dotnet.boot.config.json rather than hand-crafting config.
- Add a startup assertion in tests that calls validateLoaderConfig() before create().
- When renaming the entry assembly, update every bootstrap that references its name.
- Keep the entry assembly name in a single constant shared between .csproj and bootstrap.
When it happens
Trigger: Constructing dotnet.withConfig({}) without mainAssemblyName. Calling create()/runMain() before withMainAssembly(). Bootstrapping from a malformed dotnet.*.js script tag where the data-main attribute was removed. Custom bootstrap that skips the withMainAssembly step.
Common situations: Copied a sample config and forgot the mainAssemblyName line. Renamed the entry assembly (e.g. from App.dll to MyApp.dll) without updating the bootstrap. Used createDotnetRuntime with a partial config object. The MSBuild <WasmMainAssemblyPath> was unset so the generated config omits the name.
Related errors
- Invalid config, resources is not set
- Can't use moduleFactory callback of createDotnetRuntime…
- invariant globalization mode is inactive and no ICU data…
- Loader configuration error: 'resources.coreAssembly' is…
- max-heap-size must be an integer.\n
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/b6b5b6240743f12b.
Report an issue: GitHub.
Appendix: source
Thrown at src/native/libs/Common/JavaScript/loader/config.ts:15
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
import type { Assets, LoaderConfig, LoaderConfigInternal } from "./types";
import { browserVirtualAppBase } from "./per-module";
export const loaderConfig: LoaderConfigInternal = {};
export function getLoaderConfig(): LoaderConfig {
return loaderConfig;
}
export function validateLoaderConfig(): void {
if (!loaderConfig.mainAssemblyName) {
throw new Error("Loader configuration error: 'mainAssemblyName' is required.");
}
if (!loaderConfig.resources || !loaderConfig.resources.coreAssembly || loaderConfig.resources.coreAssembly.length === 0) {
throw new Error("Loader configuration error: 'resources.coreAssembly' is required and must contain at least one assembly.");
}
}
export function mergeLoaderConfig(source: Partial<LoaderConfigInternal>): void {
defaultConfig(loaderConfig);
normalizeConfig(source);
mergeConfigs(loaderConfig, source);
}
function mergeConfigs(target: LoaderConfigInternal, source: Partial<LoaderConfigInternal>): LoaderConfigInternal {
// no need to merge the same object
if (target === source || source === undefined || source === null) return target;
// Merge collections: target values first, then source values appended/spread on top.
mergeResources(target.resources!, source.resources!);View on GitHub (pinned to 60108ba66e)