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

  1. Call builder.withMainAssembly('MyApp.dll') before create()/runMain().
  2. Or pass mainAssemblyName inside withConfig({ mainAssemblyName: 'MyApp.dll', resources: {...} }).
  3. If using the generated dotnet.boot.config.json, ensure the build produced it; check the <WasmMainAssemblyPath> MSBuild property.
  4. 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

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


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)