dotnet/runtime · error · Error

Loader configuration error: 'resources.coreAssembly' is…

Error message

Loader configuration error: 'resources.coreAssembly' is required and must contain at least one assembly.

What it means

validateLoaderConfig() throws when resources is missing, resources.coreAssembly is missing, or coreAssembly array is empty. coreAssembly holds the framework assemblies (System.Private.CoreLib etc.) that must be present before any user code runs. The boot manifest produced by MSBuild populates this; an empty array means the publish output is incomplete.

Solutions

  1. Use the dotnet.runtimeconfig.json / dotnet.boot.config.json produced by dotnet publish — do not handcraft resources.
  2. If merging configs, ensure the source contains coreAssembly before mergeLoaderConfig runs.
  3. Re-run dotnet publish to regenerate the manifest.
  4. Verify the SDK version is consistent (coreAssembly was introduced for partitioned framework downloads).

Example fix

// before
builder.withConfig({ mainAssemblyName: 'App.dll', resources: {} });

// after: load the generated manifest
const config = await fetch('./_framework/dotnet.boot.config.json').then(r => r.json());
builder.withConfig(config);
Defensive patterns

Strategy: validation

Validate before calling

function hasCoreAssemblies(cfg: any): boolean {
  return Array.isArray(cfg?.resources?.coreAssembly) && cfg.resources.coreAssembly.length > 0;
}

Type guard

function isValidResources(r: unknown): r is { coreAssembly: unknown[] } {
  return !!r && typeof r === 'object' && Array.isArray((r as any).coreAssembly) && (r as any).coreAssembly.length > 0;
}

Try / catch

try { await dotnet.create(); } catch (e) {
  if (/resources\.coreAssembly.*required/.test((e as Error).message)) {
    // reload the boot manifest and retry
  } else throw e;
}

Prevention

When it happens

Trigger: withConfig called with resources: {} or resources.coreAssembly: []. Manually constructing a LoaderConfig without copying the framework assembly list. A custom boot config that omitted coreAssembly. Build publish output truncated.

Common situations: Hand-editing the generated boot JSON. Migrating from older SDK where coreAssembly was not a separate field. Publishing with a trimmed/incomplete _framework directory. Using a config from a different app.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/c10dc4845bebb10f. Report an issue: GitHub.

Appendix: source

Thrown at src/native/libs/Common/JavaScript/loader/config.ts:18

// 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!);
    // For scalar fields with defaults, prefer source when defined, otherwise keep target default.
    // We patch source so that Object.assign below copies the correct resolved value.
    source.appendElementOnExit = source.appendElementOnExit !== undefined ? source.appendElementOnExit : target.appendElementOnExit;

View on GitHub (pinned to 60108ba66e)