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
- Await dotnet.create() (or Module.onDotnetReady) before calling collectMetrics/collectCpuSamples/collectGcDump.
- If you must register before runtime ready, pass startup=true to use the startupJsClient slot.
- Guard with isRuntimeRunning() yourself and queue the call for onDotnetReady.
- 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
- Always await dotnet.create() before invoking diagnostic collectors.
- Use Module.onDotnetReady callback to gate diagnostic UI.
- For startup-time collection, pass startup=true instead of waiting.
- Guard collector calls behind a runtime-ready flag in your state.
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
- Diag module already loaded
- Native module already loaded
- No active JS diagnostic session
- No active JS diagnostic session
- startup diagnostic client already registered
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)