dotnet/runtime · error · Error

Runtime is not running

Error message

Runtime is not running

What it means

setupJsClient() with startup=false calls dotnetLoaderExports.isRuntimeRunning() and throws if it returns false. Diagnostic clients that are not 'startup' clients can only attach to a live runtime, because they need an active diagnostic server inside the dotnet VM to accept their connection.

Solutions

  1. Await dotnet.create() (or Module.onDotnetReady) before calling collectMetrics/collectCpuSamples/collectGcDump.
  2. If you must register before runtime ready, pass startup=true to use the startupJsClient slot.
  3. Guard with isRuntimeRunning() yourself and queue the call for onDotnetReady.
  4. Check runtimeState.dotnetReady if you have internals access.

Example fix

// before: collector called too early
collectMetrics();

// after
const runtime = await dotnet.create();
collectMetrics();
Defensive patterns

Strategy: validation

Validate before calling

function runtimeIsRunning(): boolean {
  // exposed by the loader; equivalent to dotnetLoaderExports.isRuntimeRunning()
  return typeof (globalThis as any).dotnet?.getConfig === 'function' && !!(globalThis as any).dotnet?.runtime?.runtimeId;
}

Type guard

function isRuntimeReady(): boolean {
  // Use the loader-exported helper if available
  return (globalThis as any).__dotnetRuntimeReady === true;
}

Try / catch

try { collectMetrics(); } catch (e) {
  if (/Runtime is not running/.test((e as Error).message)) {
    await dotnet.create();
    collectMetrics();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling collectMetrics()/collectCpuSamples()/collectGcDump() (which call setupJsClient with startup=false) before the runtime finished initializing. Calling setupJsClient(client) directly in onConfigLoaded or module initializer before the native module is ready.

Common situations: Invoking diagnostic collectors from a JS module initializer that runs during boot (before runtime ready). Race between await dotnet.create() and a side-effect that registers a diagnostic client. Trying to attach a collector to a runtime that exited.

Related errors


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

Appendix: source

Thrown at src/native/libs/System.Native.Browser/diagnostics/diagnostic-server-js.ts:150

        if (this.messagesToSend.length === 0) {
            return 0;
        }
        if (this.diagClient && !this.diagClient.skipDownload) {
            downloadBlob(this.messagesToSend);
        }
        this.messagesToSend = [];
        return 0;
    }
}

export function initializeJsClient() {
    nextJsClient = dotnetLoaderExports.createPromiseCompletionSource<IDiagnosticClient>();
    startupJsClient = undefined;
}

export function setupJsClient(client: IDiagnosticClient, startup?: boolean) {
    if (!startup && !dotnetLoaderExports.isRuntimeRunning()) {
        throw new Error("Runtime is not running");
    }
    if (startup) {
        if (startupJsClient) {
            throw new Error("startup diagnostic client already registered");
        }
        startupJsClient = client;
    } else {
        if (nextJsClient.isDone) {
            throw new Error("multiple clients in parallel are not allowed");
        }
        nextJsClient.resolve(client);
    }
}

export function createDiagConnectionJs(socketHandle: number, scenarioName: string): DiagnosticSession {
    if (!fromScenarioNameOnce) {
        fromScenarioNameOnce = true;
        if (scenarioName.startsWith("js://gcdump")) {

View on GitHub (pinned to 60108ba66e)