dotnet/runtime · error · Error
No active JS diagnostic session
Error message
No active JS diagnostic session
What it means
Thrown by collectGcDump() when it is called with startup not set to true while the module-level serverSession is still undefined. serverSession is only assigned once a diagnostic client (dotnet-gcdump/dotnet-counters/dotnet-trace over the diagnostic server) has completed its advertise handshake. The guard prevents starting a GC heap-dump collection against a transport that has no peer to receive the commands and data.
Solutions
- If you intend to capture a heap dump at runtime startup before any client connects, call collectGcDump(options, true) so the startup branch bypasses the session check.
- Otherwise, first ensure a diagnostic client is connected (connectDSRouter or an external dotnet-gcdump session) so that serverSession is populated before invoking collectGcDump().
- Verify initializeDS() ran successfully during dotnetInitializeModule() in diagnostics/index.ts; if the diagnostic server failed to bind, serverSession will never be created.
- Check that DOTNET_DiagnosticPorts configuration allows the in-browser diagnostic server to accept a connection.
Example fix
// before
dotnetApi.collectGcDump({ durationSeconds: 5 });
// after - capture during startup, before a client connects
dotnetApi.collectGcDump({ durationSeconds: 5 }, /* startup */ true); Defensive patterns
Strategy: validation
Validate before calling
// Before calling collectGcDump, confirm a diagnostic client is connected
// or pass startup=true to capture at boot.
import { serverSession } from "./diagnostic-server-js";
function canCollectGcDumpAtRuntime(): boolean {
return !!serverSession; // false means you must pass startup=true
}
if (!canCollectGcDumpAtRuntime()) {
console.warn("No diagnostic session; call collectGcDump(options, true) for a startup capture.");
} Type guard
null
Try / catch
null
Prevention
- Only call collectGcDump without startup=true after confirming a diagnostic client connected.
- Ensure initializeDS() runs to completion during module init so serverSession can be populated.
- For boot-time captures, always pass startup=true.
- Log whether serverSession is set before invoking diagnostic collectors.
When it happens
Trigger: Calling dotnetApi.collectGcDump() (or the runtime invoking it via the diagnostics IPC) before any diagnostic client has connected, and without passing startup=true. The same pattern exists in collectCpuSamples() and collectMetrics() which also check `!startup && !serverSession`.
Common situations: App started dotnet with diagnostics enabled but no diagnostic tool attached yet; calling collectGcDump programmatically at app startup to capture an early heap snapshot; the diagnostic server failed to initialize (initializeDS() error swallowed) so serverSession never gets set.
Related errors
- No active JS diagnostic session
- Failed on mono_wasm_get_dbg_command_info
- No active JS diagnostic session
- No active JS diagnostic session
- No active JS diagnostic session
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/cd9b020248d61544.
Report an issue: GitHub.
Appendix: source
Thrown at src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts:14
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
import type { DiagnosticCommandOptions } from "../types";
import { commandResumeRuntime, commandStopTracing, commandGcHeapDump, } from "./client-commands";
import { dotnetLoaderExports, Module } from "./cross-module";
import { serverSession, setupJsClient } from "./diagnostic-server-js";
import { IDiagnosticSession } from "./types";
export function collectGcDump(options?: DiagnosticCommandOptions, startup?: boolean): Promise<Uint8Array[]> {
if (!options) options = {};
if (!startup && !serverSession) {
throw new Error("No active JS diagnostic session");
}
const onClosePromise = dotnetLoaderExports.createPromiseCompletionSource<Uint8Array[]>();
let stopDelayedAfterLastMessage = 0;
let stopSent = false;
function onSessionStart(session: IDiagnosticSession): void {
session.sendCommand(commandResumeRuntime());
}
function onData(session: IDiagnosticSession, message: Uint8Array): void {
session.store(message);
if (!stopSent) {
// stop durationSeconds (default 1s) after last GC message on this session, there will be more messages after that
if (stopDelayedAfterLastMessage) {
clearTimeout(stopDelayedAfterLastMessage);
}
stopDelayedAfterLastMessage = Module.safeSetTimeout(() => {
stopSent = true;
session.sendCommand(commandStopTracing(session.sessionId));View on GitHub (pinned to 60108ba66e)