microsoft/aspire · error · Error

registerCancellation(signal) is ambiguous when multiple…

Error message

registerCancellation(signal) is ambiguous when multiple AspireClient instances are connected. Pass the client explicitly.

What it means

When multiple AspireClient instances are connected simultaneously, registerCancellation(signal) cannot determine which client should own the cancellation registration, so it refuses to guess and throws. This prevents cancellation signals from silently binding to the wrong client.

Solutions

  1. Pass the client explicitly: registerCancellation(signal, client).
  2. Disconnect (client.close()/disconnect()) stale clients so only one remains connected.
  3. Scope clients per test/module and always clean up in teardown.
  4. Track connected clients in a registry to make the intended target explicit.

Example fix

// before
registerCancellation(signal); // ambiguous: 2 clients connected

// after
registerCancellation(signal, appHostClient); // explicit target
Defensive patterns

Strategy: validation

Validate before calling

// Ensure only one connected client, or always pass one explicitly
registerCancellation(signal, appHostClient); // explicit target avoids ambiguity

Type guard

function hasSingleConnectedClient(clients: AspireClient[]): AspireClient | null {
  const connected = clients.filter(c => c.connected);
  return connected.length === 1 ? connected[0] : null;
}

Try / catch

try {
  registerCancellation(signal);
} catch (e) {
  if (e instanceof Error && e.message.includes("is ambiguous")) {
    registerCancellation(signal, intendedClient); // disambiguate
  } else throw e;
}

Prevention

When it happens

Trigger: Calling registerCancellation(signal) with no explicit client while two or more AspireClients are connected (e.g. an app host client plus a dashboard/debug client); leaving a previous test's client connected while opening a new one.

Common situations: Test suites that share a process across cases without disconnecting clients; apps that connect to multiple environments concurrently; refactors that added a second client but not explicit registration targets.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/cceef0ae87311d44. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.mts:581

const connectedClients = new Set<AspireClient>();

function resolveCancellationClient(client?: AspireClientRpc): AspireClientRpc {
    if (client) {
        return client;
    }

    if (connectedClients.size === 1) {
        return connectedClients.values().next().value as AspireClient;
    }

    if (connectedClients.size === 0) {
        throw new Error(
            'registerCancellation(signal) requires a connected AspireClient. ' +
            'Pass the client explicitly or connect the client first.'
        );
    }

    throw new Error(
        'registerCancellation(signal) is ambiguous when multiple AspireClient instances are connected. ' +
        'Pass the client explicitly.'
    );
}

function isAspireClientLike(value: unknown): value is AspireClientRpc {
    if (!value || typeof value !== 'object') {
        return false;
    }

    const candidate = value as {
        invokeCapability?: unknown;
        cancelToken?: unknown;
        connected?: unknown;
    };

    return typeof candidate.invokeCapability === 'function'
        && typeof candidate.cancelToken === 'function'

View on GitHub (pinned to 25830f84bd)