{"record":{"id":"677eaf5b86b99733","repo":"dotnet/runtime","slug":"invalid-config-resources-is-not-set-677eaf","errorCode":null,"errorMessage":"Invalid config, resources is not set","messagePattern":"Invalid config, resources is not set","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/Common/JavaScript/loader/run.ts","lineNumber":27,"sourceCode":"import { getIcuResourceName } from \"./icu\";\nimport { loaderConfig, validateLoaderConfig } from \"./config\";\nimport { fetchAssembly, fetchIcu, fetchNativeSymbols, fetchPdb, fetchSatelliteAssemblies, fetchVfs, fetchMainWasm, loadDotnetModule, loadJSModule, nativeModulePromiseController, verifyAllAssetsDownloaded, callLibraryInitializerOnRuntimeReady, callLibraryInitializerOnRuntimeConfigLoaded, prefetchAllResources, prefetchJSModuleLinks, resolveAllDownloadsQueued } from \"./assets\";\nimport { initPolyfillsLoader } from \"./polyfills\";\nimport { validateEngineFeatures } from \"./bootstrap\";\n\nconst runMainPromiseController = createPromiseCompletionSource<number>();\n\ntype DownloadMode = \"none\" | \"cacheOnly\" | \"intoMemory\";\nlet downloadMode: DownloadMode = \"none\";\nlet downloadDeferred: PromiseCompletionSource<void> | undefined;\nlet downloadedIntoMemory = false;\nlet configInitialized = false;\nlet modulesAfterConfigLoadedCache: [JsAsset, Promise<any>][] = [];\n\n// many things happen in parallel here, but order matters for performance!\n// ideally we want to utilize network and CPU at the same time\nexport async function createRuntime(downloadOnly: boolean, httpCacheOnly: boolean = false): Promise<any> {\n    if (!loaderConfig.resources || !loaderConfig.resources.coreAssembly || !loaderConfig.resources.coreAssembly.length) throw new Error(\"Invalid config, resources is not set\");\n    try {\n        runtimeState.creatingRuntime = true;\n\n        // Re-entrancy guard: await any in-flight download, skip if already at requested level\n        if (downloadOnly) {\n            if (downloadDeferred) {\n                await downloadDeferred.promise;\n            }\n            if (downloadMode === \"intoMemory\" || (httpCacheOnly && downloadMode === \"cacheOnly\")) {\n                return;\n            }\n            downloadDeferred = createPromiseCompletionSource<void>();\n        }\n\n        // Fast path: download() already loaded everything into memory, create() just needs to init\n        if (downloadedIntoMemory && !downloadOnly) {\n            Module.runtimeKeepalivePush();\n            await initializeCoreCLR();","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/Common/JavaScript/loader/run.ts#L9-L45","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst runtime = await dotnet.create(); // resources not set yet\n\n// after\nconst boot = await fetch('./_framework/dotnet.boot.config.json').then(r => r.json());\ndotnet.withConfig(boot);\nconst runtime = await dotnet.create();","handlingStrategy":"validation","validationCode":"function isResourcesConfigured(cfg: any): boolean {\n  return !!cfg?.resources && Array.isArray(cfg.resources.coreAssembly) && cfg.resources.coreAssembly.length > 0;\n}\nif (!isResourcesConfigured(loaderConfig)) {\n  throw new Error('Boot config not loaded yet');\n}","typeGuard":"function isRuntimeReadyConfig(c: unknown): boolean {\n  return !!c && typeof c === 'object' && Array.isArray((c as any).resources?.coreAssembly) && (c as any).resources.coreAssembly.length > 0;\n}","tryCatchPattern":"try { await dotnet.create(); } catch (e) {\n  if (/resources is not set/.test((e as Error).message)) {\n    const boot = await fetch('./_framework/dotnet.boot.config.json').then(r => r.json());\n    dotnet.withConfig(boot);\n    await dotnet.create();\n  } else throw e;\n}","preventionTips":["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."],"tags":["configuration","loader","startup","resources"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}