dotnet/runtime · error · Error
multiple clients in parallel are not allowed
Error message
multiple clients in parallel are not allowed
What it means
Thrown by setupJsClient (runtime path) when nextJsClient.isDone is already true, meaning a runtime diagnostic client is already pending or active. The JS diagnostic protocol supports one client at a time per session.
Source
Thrown at src/native/libs/System.Native.Browser/diagnostics/diagnostic-server-js.ts:159
}
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")) {
collectGcDump({}, true);
}
if (scenarioName.startsWith("js://counters")) {
collectMetrics({}, true);
}
if (scenarioName.startsWith("js://cpu-samples")) {
collectCpuSamples({}, true);
}
const dotnetDiagnosticClient: FnClientProvider = (globalThis as any).dotnetDiagnosticClient;View on GitHub (pinned to 290d5ab72c)
Solutions
- Await the previous collect* promise before starting a new diagnostic collection.
- Serialize diagnostic requests through a single-slot queue.
Example fix
// before: overlapping runtime clients collectMetrics(); collectGcDump(); // throws: parallel not allowed // after: await before starting the next await collectMetrics(); await collectGcDump();
Defensive patterns
Strategy: validation
Validate before calling
// Serialize runtime diagnostic collections through a single-slot lock
let diagInProgress = null;
async function runOneAtATime(fn, opts) {
while (diagInProgress) await diagInProgress;
diagInProgress = fn(opts);
try { return await diagInProgress; } finally { diagInProgress = null; }
} Prevention
- Await the previous collect* promise before starting the next.
- Wrap diagnostics in a queue/lock so UI cannot trigger overlapping sessions.
- Disable the trigger button while a collection is in flight.
When it happens
Trigger: Calling collectMetrics()/collectGcDump()/collectCpuSamples() a second time while the first session is still open and its promise has not resolved.
Common situations: UI buttons triggering overlapping traces; forgetting to await the previous collect promise; a retry fired before the first attempt settled.
Related errors
- startup diagnostic client already registered
- No active session to reconnect
- No active JS diagnostic session
- No active JS diagnostic session
- method instrumentation is not enabled, please enable it with
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/af9dfed632a4e514.
Report an issue: GitHub.