dotnet/runtime · error · Error

Invalid jsThreadBlockingMode

Error message

Invalid jsThreadBlockingMode

What it means

install_main_synchronization_context maps config.jsThreadBlockingMode to an integer via a switch that recognizes exactly four values (PreventSynchronousJSExport, ThrowWhenBlockingWait, WarnWhenBlockingWait, DangerousAllowBlockingWait). Any other value reaches the default branch and is rejected as invalid.

Source

Thrown at src/mono/browser/runtime/managed-exports.ts:273

        const arg2 = get_arg(args, 3);
        set_arg_intptr(arg1, mono_wasm_main_thread_ptr() as any);

        // sync with JSHostImplementation.Types.cs
        switch (jsThreadBlockingMode) {
            case JSThreadBlockingMode.PreventSynchronousJSExport:
                set_arg_i32(arg2, 0);
                break;
            case JSThreadBlockingMode.ThrowWhenBlockingWait:
                set_arg_i32(arg2, 1);
                break;
            case JSThreadBlockingMode.WarnWhenBlockingWait:
                set_arg_i32(arg2, 2);
                break;
            case JSThreadBlockingMode.DangerousAllowBlockingWait:
                set_arg_i32(arg2, 100);
                break;
            default:
                throw new Error("Invalid jsThreadBlockingMode");
        }

        // this block is like invoke_sync_jsexport() but without assert_js_interop()
        cwraps.mono_wasm_invoke_jsexport(managedExports.InstallMainSynchronizationContext!, args);
        if (is_args_exception(args)) {
            const exc = get_arg(args, 0);
            throw marshal_exception_to_js(exc);
        }
        return get_arg_gc_handle(res) as any;
    } catch (e) {
        mono_log_error("install_main_synchronization_context failed", e);
        throw e;
    }
}

export function invoke_async_jsexport (managedTID: PThreadPtr, method: MonoMethod, args: JSMarshalerArguments, size: number): void {
    assert_js_interop();
    if (!WasmEnableThreads || runtimeHelpers.isManagedRunningOnCurrentThread) {

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Set config.jsThreadBlockingMode to exactly one of: 'PreventSynchronousJSExport', 'ThrowWhenBlockingWait', 'WarnWhenBlockingWait', 'DangerousAllowBlockingWait'.
  2. Omit the setting entirely so config.ts:203 applies the default 'PreventSynchronousJSExport'.

Example fix

// before
config.jsThreadBlockingMode = 'PreventSync';
// after
config.jsThreadBlockingMode = 'PreventSynchronousJSExport';
Defensive patterns

Strategy: validation

Validate before calling

const VALID = new Set(['PreventSynchronousJSExport', 'ThrowWhenBlockingWait', 'WarnWhenBlockingWait', 'DangerousAllowBlockingWait']);
if (config.jsThreadBlockingMode != null && !VALID.has(config.jsThreadBlockingMode)) {
  throw new Error(`Invalid jsThreadBlockingMode '${config.jsThreadBlockingMode}'. Valid: ${[...VALID].join(', ')}`);
}

Type guard

function isJSThreadBlockingMode(v): v is 'PreventSynchronousJSExport' | 'ThrowWhenBlockingWait' | 'WarnWhenBlockingWait' | 'DangerousAllowBlockingWait' {
  return v === 'PreventSynchronousJSExport' || v === 'ThrowWhenBlockingWait' || v === 'WarnWhenBlockingWait' || v === 'DangerousAllowBlockingWait';
}

Prevention

When it happens

Trigger: Passing an unrecognized or misspelled string in config.jsThreadBlockingMode (e.g. 'PreventSync', 'Throw', a number, or undefined handling bypassed). The deputy thread calls install_main_synchronization_context with config.jsThreadBlockingMode at startup.

Common situations: Typo in the config object; copying a value from an older/newer version whose enum names differ; passing a numeric instead of the enum string.

Related errors


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