dotnet/runtime · error · Error

Module.ready couldn't be redefined.

Error message

Module.ready couldn't be redefined.

What it means

Thrown by prepareEmscripten when the moduleFactory callback returns an object that has a `ready` property. The Emscripten module's `ready` field is reserved/managed internally by the runtime, so the runtime refuses to let user config redefine it.

Source

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

}

let emscriptenPrepared = false;
async function prepareEmscripten (moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)) {
    if (emscriptenPrepared) {
        return;
    }
    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}`);

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Remove the `ready` property from the config object returned by your moduleFactory callback.
  2. If you need a ready signal, use the returned RuntimeAPI promise (await createDotnetRuntime(...)) or the runtime's ready event instead of setting Module.ready.
  3. Pass only supported DotnetModuleConfig keys in the callback.

Example fix

// before: factory returns config with ready
// createDotnetRuntime(() => ({ ready: myPromise, config: {...} }));

// after: drop ready; use the returned promise
const dotnet = await createDotnetRuntime(() => ({ config: {...} }));
// dotnet is ready once the promise resolves
Defensive patterns

Strategy: validation

Validate before calling

const factory = () => {
  const cfg = { config: monoConfig };
  delete (cfg as any).ready; // never return ready
  return cfg;
};

Type guard

function configHasNoReady(cfg: any): boolean {
  return cfg == null || typeof cfg !== 'object' || !('ready' in cfg);
}

Prevention

When it happens

Trigger: Produced when createDotnetRuntime is called with a moduleFactory function whose returned config object includes a `ready` key (e.g. { ready: ... }).

Common situations: Copying an Emscripten-style config that sets Module.ready; migrating from a raw Emscripten setup into the dotnet runtime builder; a third-party wrapper that injects ready.

Related errors


AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06). Data as JSON: /api/errors/1c60352ed7de9a2a. Report an issue: GitHub.