dotnet/runtime · error · Error
Invalid config, resources is not set
Error message
Invalid config, resources is not set
What it means
createRuntime() guards its first line: if loaderConfig.resources or resources.coreAssembly is missing/empty, it throws before doing any work. This is the runtime-side twin of error 107 (validateLoaderConfig) — run.ts does its own precondition check rather than relying solely on validateLoaderConfig because createRuntime can be reached directly (e.g. download() path).
Solutions
- Ensure withConfig(bootConfig) is awaited and the config has resources.coreAssembly populated before create()/download().
- If loading config asynchronously, await it before invoking the builder.
- Reproduce the same flow the generated dotnet.*.js uses — it always awaits the boot JSON.
- Cross-check with validateLoaderConfig() output; if that throws 107, fix the config first.
Example fix
// before
const runtime = await dotnet.create(); // resources not set yet
// after
const boot = await fetch('./_framework/dotnet.boot.config.json').then(r => r.json());
dotnet.withConfig(boot);
const runtime = await dotnet.create(); Defensive patterns
Strategy: validation
Validate before calling
function isResourcesConfigured(cfg: any): boolean {
return !!cfg?.resources && Array.isArray(cfg.resources.coreAssembly) && cfg.resources.coreAssembly.length > 0;
}
if (!isResourcesConfigured(loaderConfig)) {
throw new Error('Boot config not loaded yet');
} Type guard
function isRuntimeReadyConfig(c: unknown): boolean {
return !!c && typeof c === 'object' && Array.isArray((c as any).resources?.coreAssembly) && (c as any).resources.coreAssembly.length > 0;
} Try / catch
try { await dotnet.create(); } catch (e) {
if (/resources is not set/.test((e as Error).message)) {
const boot = await fetch('./_framework/dotnet.boot.config.json').then(r => r.json());
dotnet.withConfig(boot);
await dotnet.create();
} else throw e;
} Prevention
- Always await the boot config fetch before calling create().
- Mirror the generated dotnet.*.js bootstrap flow.
- Add a guard: assert loaderConfig.resources?.coreAssembly?.length before createRuntime.
- Re-run dotnet publish if the boot config is missing coreAssembly.
When it happens
Trigger: Calling createRuntime before mergeLoaderConfig populated resources. Loading a config JSON that had no resources block. A bootstrap script that calls run before the boot config fetch resolved. A custom loader entry that skips withConfig.
Common situations: Race condition: code calls dotnet.create() before the fetch for dotnet.boot.config.json completes. Manually crafted config that omits resources. Mixing versions where an old bootstrap feeds a new loader.
Related errors
- Loader configuration error: 'mainAssemblyName' is required.
- 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/677eaf5b86b99733.
Report an issue: GitHub.
Appendix: source
Thrown at src/native/libs/Common/JavaScript/loader/run.ts:27
import { getIcuResourceName } from "./icu";
import { loaderConfig, validateLoaderConfig } from "./config";
import { fetchAssembly, fetchIcu, fetchNativeSymbols, fetchPdb, fetchSatelliteAssemblies, fetchVfs, fetchMainWasm, loadDotnetModule, loadJSModule, nativeModulePromiseController, verifyAllAssetsDownloaded, callLibraryInitializerOnRuntimeReady, callLibraryInitializerOnRuntimeConfigLoaded, prefetchAllResources, prefetchJSModuleLinks, resolveAllDownloadsQueued } from "./assets";
import { initPolyfillsLoader } from "./polyfills";
import { validateEngineFeatures } from "./bootstrap";
const runMainPromiseController = createPromiseCompletionSource<number>();
type DownloadMode = "none" | "cacheOnly" | "intoMemory";
let downloadMode: DownloadMode = "none";
let downloadDeferred: PromiseCompletionSource<void> | undefined;
let downloadedIntoMemory = false;
let configInitialized = false;
let modulesAfterConfigLoadedCache: [JsAsset, Promise<any>][] = [];
// many things happen in parallel here, but order matters for performance!
// ideally we want to utilize network and CPU at the same time
export async function createRuntime(downloadOnly: boolean, httpCacheOnly: boolean = false): Promise<any> {
if (!loaderConfig.resources || !loaderConfig.resources.coreAssembly || !loaderConfig.resources.coreAssembly.length) throw new Error("Invalid config, resources is not set");
try {
runtimeState.creatingRuntime = true;
// Re-entrancy guard: await any in-flight download, skip if already at requested level
if (downloadOnly) {
if (downloadDeferred) {
await downloadDeferred.promise;
}
if (downloadMode === "intoMemory" || (httpCacheOnly && downloadMode === "cacheOnly")) {
return;
}
downloadDeferred = createPromiseCompletionSource<void>();
}
// Fast path: download() already loaded everything into memory, create() just needs to init
if (downloadedIntoMemory && !downloadOnly) {
Module.runtimeKeepalivePush();
await initializeCoreCLR();View on GitHub (pinned to 60108ba66e)