BabylonJS/Babylon.js · error · Error

Disconnect failed

Error message

Disconnect failed

What it means

The outBus setter on AbstractSoundSource first disconnects the source from its current output bus via this._disconnect(this._outBus). If that returns false — because the bus no longer lists this source as an upstream node, e.g. the bus was disposed (its onDisposeObservable callback already nulled _outBus elsewhere) or the link was removed out-of-band — the setter throws "Disconnect failed". This indicates the source/bus connection bookkeeping is inconsistent when reassigning outBus.

Source

Thrown at packages/dev/core/src/AudioV2/abstractAudio/abstractSoundSource.ts:94

     * The output bus for the sound.
     * @see {@link AudioEngineV2.defaultMainBus}
     */
    public get outBus(): Nullable<PrimaryAudioBus> {
        return this._outBus;
    }

    public set outBus(outBus: Nullable<PrimaryAudioBus>) {
        if (this._outBus === outBus) {
            return;
        }

        if (this._outBus) {
            if (this._onOutBusDisposed) {
                this._outBus.onDisposeObservable.removeCallback(this._onOutBusDisposed);
                this._onOutBusDisposed = null;
            }
            if (!this._disconnect(this._outBus)) {
                throw new Error("Disconnect failed");
            }
        }

        this._outBus = outBus;

        if (this._outBus) {
            this._onOutBusDisposed = () => {
                this._outBus = null;
            };
            this._outBus.onDisposeObservable.add(this._onOutBusDisposed);
            if (!this._connect(this._outBus)) {
                throw new Error("Connect failed");
            }
        }
    }

    /**
     * The spatial audio features.

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Verify the current outBus is still alive before reassigning: check sound.outBus is non-null and the bus is not disposed; if the bus was disposed, _outBus may already be stale — re-check your lifecycle ordering.
  2. Disconnect explicitly before reassigning: call sound.outBus = null (or bus.disconnect(sound)) in a guarded way, then assign the new bus.
  3. Ensure only one code path owns bus reassignment; remove duplicate dispose/disconnect callbacks that can race the setter.
  4. Wrap the assignment in try/catch and, on failure, check whether the old bus was disposed; re-create the source or bus if the graph is inconsistent.
  5. If you subclass the sound source, make sure _onDisconnect returns true for valid removals.

Example fix

// before
sound.outBus = musicBus; // throws if oldBus was disposed earlier

// after
if (sound.outBus && !sound.outBus.isDisposed) {
    sound.outBus = null; // clean detach first
}
sound.outBus = musicBus;
Defensive patterns

Strategy: try-catch

Validate before calling

// re-route only if the current bus is alive and actually connected
if (sound.outBus != null && !sound.outBus.isDisposed) {
    sound.outBus = null; // clean detach
}
sound.outBus = newBus;

Type guard

function hasLiveOutBus(source) {
    return source.outBus != null && !source.outBus.isDisposed;
}

Try / catch

try {
    sound.outBus = newBus;
} catch (e) {
    if (e.message === "Disconnect failed") {
        // old bus was disposed out-of-band; recreate source or reconnect
        sound.outBus = null;
        sound.outBus = newBus;
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Assigning sound.outBus = newBus when: the current bus was disposed between connection and assignment (the dispose callback nulls _outBus but the internal sets are inconsistent), the source was already disconnected from the bus via dispose() or manual disconnect(), or a subclass's _onDisconnect override returns false. Note _outBus !== outBus guard means a plain reassignment to the same bus is a no-op.

Common situations: Re-routing a sound after the previous bus was disposed in an audio-graph rebuild; hot-swapping buses during scene teardown while another callback disposed the old bus; assigning outBus from a stale reference kept across engine resets.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/5194656a6e2ec974. Report an issue: GitHub.