dotnet/runtime · error · Error

Can't use moduleFactory callback of createDotnetRuntime…

Error message

Can't use moduleFactory callback of createDotnetRuntime function.

What it means

Thrown by prepareEmscripten() when the moduleFactory argument is neither a function nor an object (e.g., it is a number, string, boolean, null without falling through, or symbol). The createDotnetRuntime API only accepts these two shapes: a config object or a factory function that receives the RuntimeAPI and returns a config object. Any other type is a programming error.

Solutions

  1. Ensure the argument passed to createDotnetRuntime is either a DotnetModuleConfig object or a function returning one.
  2. If loading config from JSON, parse it first: createDotnetRuntime(JSON.parse(configString)).
  3. Check the argument type before calling: if (typeof config !== 'object' && typeof config !== 'function') throw new TypeError(...).
  4. Use the high-level dotnet.create() API instead of the low-level createDotnetRuntime to avoid manual module factory handling.

Example fix

// before (string passed by mistake)
const api = await createDotnetRuntime('./dotnet.config.json');

// after (parsed object)
const config = await fetch('./dotnet.config.json').then(r => r.json());
const api = await createDotnetRuntime(config);
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate moduleFactory type before calling createDotnetRuntime
function validateModuleFactory(factory: unknown) {
  if (typeof factory !== 'function' && (typeof factory !== 'object' || factory === null)) {
    throw new TypeError('moduleFactory must be a function or a config object');
  }
}
validateModuleFactory(myConfig);

Type guard

function isModuleFactory(factory: unknown): factory is Function | object {
  return typeof factory === 'function' || (typeof factory === 'object' && factory !== null);
}

Prevention

When it happens

Trigger: Passing a non-object, non-function value as the moduleFactory argument to createDotnetRuntime() or createEmscripten(). For example passing null (after the emscriptenModule check), a string URL, a number, or a Boolean wrapper.

Common situations: Incorrectly wiring up the runtime in a bundler (webpack/rollup) where the import resolves to a string URL instead of a module config object. Passing a config JSON string instead of a parsed object. Accidentally passing undefined from a failed dynamic import.

Related errors


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

Appendix: source

Thrown at src/mono/browser/runtime/loader/run.ts:308

    emscriptenPrepared = true;
    if (ENVIRONMENT_IS_WEB && loaderHelpers.config.forwardConsole && typeof globalThis.WebSocket != "undefined") {
        setup_proxy_console("main", globalThis.console, globalThis.location.origin);
    }
    mono_assert(emscriptenModule, "Null moduleConfig");
    mono_assert(loaderHelpers.config, "Null moduleConfig.config");

    // extract ModuleConfig
    if (typeof moduleFactory === "function") {
        const extension = moduleFactory(globalObjectsRoot.api) as any;
        if (extension.ready) {
            throw new Error("Module.ready couldn't be redefined.");
        }
        Object.assign(emscriptenModule, extension);
        deep_merge_module(emscriptenModule, extension);
    } else if (typeof moduleFactory === "object") {
        deep_merge_module(emscriptenModule, moduleFactory);
    } else {
        throw new Error("Can't use moduleFactory callback of createDotnetRuntime function.");
    }

    await detect_features_and_polyfill(emscriptenModule);
}

export async function createEmscripten (moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)): Promise<RuntimeAPI | EmscriptenModuleInternal> {
    await prepareEmscripten(moduleFactory);

    if (BuildConfiguration === "Debug" && !ENVIRONMENT_IS_WORKER) {
        mono_log_info(`starting script ${loaderHelpers.scriptUrl}`);
        mono_log_info(`starting in ${loaderHelpers.scriptDirectory}`);
    }
    if (loaderHelpers.config.exitOnUnhandledError) {
        installUnhandledErrorHandler();
    }

    registerEmscriptenExitHandlers();

View on GitHub (pinned to 60108ba66e)