{"record":{"id":"cd9b020248d61544","repo":"dotnet/runtime","slug":"no-active-js-diagnostic-session-cd9b02","errorCode":null,"errorMessage":"No active JS diagnostic session","messagePattern":"No active JS diagnostic session","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts","lineNumber":14,"sourceCode":"// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nimport type { DiagnosticCommandOptions } from \"../types\";\n\nimport { commandResumeRuntime, commandStopTracing, commandGcHeapDump, } from \"./client-commands\";\nimport { dotnetLoaderExports, Module } from \"./cross-module\";\nimport { serverSession, setupJsClient } from \"./diagnostic-server-js\";\nimport { IDiagnosticSession } from \"./types\";\n\nexport function collectGcDump(options?: DiagnosticCommandOptions, startup?: boolean): Promise<Uint8Array[]> {\n    if (!options) options = {};\n    if (!startup && !serverSession) {\n        throw new Error(\"No active JS diagnostic session\");\n    }\n\n    const onClosePromise = dotnetLoaderExports.createPromiseCompletionSource<Uint8Array[]>();\n    let stopDelayedAfterLastMessage = 0;\n    let stopSent = false;\n    function onSessionStart(session: IDiagnosticSession): void {\n        session.sendCommand(commandResumeRuntime());\n    }\n    function onData(session: IDiagnosticSession, message: Uint8Array): void {\n        session.store(message);\n        if (!stopSent) {\n            // stop durationSeconds (default 1s) after last GC message on this session, there will be more messages after that\n            if (stopDelayedAfterLastMessage) {\n                clearTimeout(stopDelayedAfterLastMessage);\n            }\n            stopDelayedAfterLastMessage = Module.safeSetTimeout(() => {\n                stopSent = true;\n                session.sendCommand(commandStopTracing(session.sessionId));","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts#L1-L32","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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."],"exampleFix":"// before\ndotnetApi.collectGcDump({ durationSeconds: 5 });\n\n// after - capture during startup, before a client connects\ndotnetApi.collectGcDump({ durationSeconds: 5 }, /* startup */ true);","handlingStrategy":"validation","validationCode":"// Before calling collectGcDump, confirm a diagnostic client is connected\n// or pass startup=true to capture at boot.\nimport { serverSession } from \"./diagnostic-server-js\";\n\nfunction canCollectGcDumpAtRuntime(): boolean {\n  return !!serverSession; // false means you must pass startup=true\n}\n\nif (!canCollectGcDumpAtRuntime()) {\n  console.warn(\"No diagnostic session; call collectGcDump(options, true) for a startup capture.\");\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["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."],"tags":["diagnostics","gcdump","session","startup"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}