dotnet/runtime · error · Error
startup diagnostic client already registered
Error message
startup diagnostic client already registered
What it means
Thrown by setupJsClient when startup=true but a startup diagnostic client (startupJsClient) is already registered. The diagnostic subsystem accepts at most one startup client because there is a single startup handshake with the runtime.
Source
Thrown at src/native/libs/System.Native.Browser/diagnostics/diagnostic-server-js.ts:154
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")) {
collectGcDump({}, true);
}
if (scenarioName.startsWith("js://counters")) {
collectMetrics({}, true);View on GitHub (pinned to 290d5ab72c)
Solutions
- Register exactly one startup diagnostic client.
- Run additional collections at runtime (startup=false) after the startup capture completes.
Example fix
// before: two startup clients collide
collectMetrics({}, true);
collectGcDump({}, true); // throws
// after: one startup, the rest at runtime
await collectMetrics({}, true);
await collectGcDump(); // runtime path after startup completes Defensive patterns
Strategy: validation
Validate before calling
// Track startup registration externally so you never double-register
let startupRegistered = false;
function registerStartupCollect(fn, opts) {
if (startupRegistered) throw new Error('A startup diagnostic client is already registered.');
startupRegistered = true;
return fn(opts, true);
} Prevention
- Register exactly one startup diagnostic client.
- Do not combine a DOTNET_DiagnosticPorts startup scenario with an explicit collect*(opts, true).
- Run all other collections at runtime after the startup client finishes.
When it happens
Trigger: Calling setupJsClient (or two collect* functions) with startup=true more than once, e.g. collectMetrics({}, true) followed by collectGcDump({}, true) at boot.
Common situations: Configuring DOTNET_DiagnosticPorts to a startup scenario AND explicitly calling a collect function with startup=true; an init helper that double-registers.
Related errors
- multiple clients in parallel are not allowed
- Unrecognized asset behavior:${asset.behavior}, for asset ${a
- No active session to reconnect
- No active JS diagnostic session
- No active JS diagnostic session
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/029af87324a485d8.
Report an issue: GitHub.