dotnet/aspnetcore · error · Error

A reconnectPolicy has already been set.

Error message

A reconnectPolicy has already been set.

What it means

Thrown at HubConnectionBuilder.ts:180 by `withAutomaticReconnect()` if `this.reconnectPolicy` is already set. The builder enforces single configuration of the reconnect policy to avoid ambiguity about which policy wins; calling withAutomaticReconnect twice (in any overload form) trips the guard.

Source

Thrown at src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts:180

     * By default, the client will wait 0, 2, 10 and 30 seconds respectively before trying up to 4 reconnect attempts.
     */
    public withAutomaticReconnect(): HubConnectionBuilder;

    /** Configures the {@link @microsoft/signalr.HubConnection} to automatically attempt to reconnect if the connection is lost.
     *
     * @param {number[]} retryDelays An array containing the delays in milliseconds before trying each reconnect attempt.
     * The length of the array represents how many failed reconnect attempts it takes before the client will stop attempting to reconnect.
     */
    public withAutomaticReconnect(retryDelays: number[]): HubConnectionBuilder;

    /** Configures the {@link @microsoft/signalr.HubConnection} to automatically attempt to reconnect if the connection is lost.
     *
     * @param {IRetryPolicy} reconnectPolicy An {@link @microsoft/signalR.IRetryPolicy} that controls the timing and number of reconnect attempts.
     */
    public withAutomaticReconnect(reconnectPolicy: IRetryPolicy): HubConnectionBuilder;
    public withAutomaticReconnect(retryDelaysOrReconnectPolicy?: number[] | IRetryPolicy): HubConnectionBuilder {
        if (this.reconnectPolicy) {
            throw new Error("A reconnectPolicy has already been set.");
        }

        if (!retryDelaysOrReconnectPolicy) {
            this.reconnectPolicy = new DefaultReconnectPolicy();
        } else if (Array.isArray(retryDelaysOrReconnectPolicy)) {
            this.reconnectPolicy = new DefaultReconnectPolicy(retryDelaysOrReconnectPolicy);
        } else {
            this.reconnectPolicy = retryDelaysOrReconnectPolicy;
        }

        return this;
    }

    /** Configures {@link @microsoft/signalr.HubConnection.serverTimeoutInMilliseconds} for the {@link @microsoft/signalr.HubConnection}.
     *
     * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
     */
    public withServerTimeout(milliseconds: number): HubConnectionBuilder {

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Call `withAutomaticReconnect` exactly once per builder instance.
  2. If you need to change policy, build a new HubConnectionBuilder.
  3. Refactor shared setup functions to be idempotent — track whether they already configured reconnect.
  4. Pick the single most-appropriate overload (no-arg default, delays array, or custom policy) and use only that.

Example fix

// before
builder.withAutomaticReconnect([0, 2000, 10000]).withAutomaticReconnect(); // throws

// after
builder.withAutomaticReconnect([0, 2000, 10000]);
// or for full default
builder.withAutomaticReconnect();
Defensive patterns

Strategy: validation

Validate before calling

function withReconnect(builder, policy) {
  if (builder.reconnectPolicy) {
    throw new Error('reconnectPolicy already configured on this builder');
  }
  return builder.withAutomaticReconnect(policy);
}

Type guard

function builderHasReconnect(b: HubConnectionBuilder): boolean {
  return !!(b as any).reconnectPolicy;
}

Try / catch

try { builder.withAutomaticReconnect(policy); }
catch (e) {
  if (/reconnectPolicy has already been set/.test(String(e))) {
    // already configured - skip silently or build a new builder
    return builder;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `builder.withAutomaticReconnect()` twice in a chain; calling `withAutomaticReconnect()` then `withAutomaticReconnect([0, 2000, 10000])`; calling `withAutomaticReconnect(policy)` after the no-arg overload; a config helper that adds a reconnect policy unconditionally and is then called again by app code.

Common situations: A shared builder-setup function that adds reconnect, then app code adds it again; iterating on config without realizing the builder is stateful; copy-paste between files leaving a duplicate call; conditional setup where both branches run.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/ab89aa20190d18c1. Report an issue: GitHub.