{"record":{"id":"5194656a6e2ec974","repo":"BabylonJS/Babylon.js","slug":"disconnect-failed-519465","errorCode":null,"errorMessage":"Disconnect failed","messagePattern":"Disconnect failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/AudioV2/abstractAudio/abstractSoundSource.ts","lineNumber":94,"sourceCode":"     * The output bus for the sound.\n     * @see {@link AudioEngineV2.defaultMainBus}\n     */\n    public get outBus(): Nullable<PrimaryAudioBus> {\n        return this._outBus;\n    }\n\n    public set outBus(outBus: Nullable<PrimaryAudioBus>) {\n        if (this._outBus === outBus) {\n            return;\n        }\n\n        if (this._outBus) {\n            if (this._onOutBusDisposed) {\n                this._outBus.onDisposeObservable.removeCallback(this._onOutBusDisposed);\n                this._onOutBusDisposed = null;\n            }\n            if (!this._disconnect(this._outBus)) {\n                throw new Error(\"Disconnect failed\");\n            }\n        }\n\n        this._outBus = outBus;\n\n        if (this._outBus) {\n            this._onOutBusDisposed = () => {\n                this._outBus = null;\n            };\n            this._outBus.onDisposeObservable.add(this._onOutBusDisposed);\n            if (!this._connect(this._outBus)) {\n                throw new Error(\"Connect failed\");\n            }\n        }\n    }\n\n    /**\n     * The spatial audio features.","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/AudioV2/abstractAudio/abstractSoundSource.ts#L76-L112","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Disconnect explicitly before reassigning: call sound.outBus = null (or bus.disconnect(sound)) in a guarded way, then assign the new bus.","Ensure only one code path owns bus reassignment; remove duplicate dispose/disconnect callbacks that can race the setter.","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.","If you subclass the sound source, make sure _onDisconnect returns true for valid removals."],"exampleFix":"// before\nsound.outBus = musicBus; // throws if oldBus was disposed earlier\n\n// after\nif (sound.outBus && !sound.outBus.isDisposed) {\n    sound.outBus = null; // clean detach first\n}\nsound.outBus = musicBus;","handlingStrategy":"try-catch","validationCode":"// re-route only if the current bus is alive and actually connected\nif (sound.outBus != null && !sound.outBus.isDisposed) {\n    sound.outBus = null; // clean detach\n}\nsound.outBus = newBus;","typeGuard":"function hasLiveOutBus(source) {\n    return source.outBus != null && !source.outBus.isDisposed;\n}","tryCatchPattern":"try {\n    sound.outBus = newBus;\n} catch (e) {\n    if (e.message === \"Disconnect failed\") {\n        // old bus was disposed out-of-band; recreate source or reconnect\n        sound.outBus = null;\n        sound.outBus = newBus;\n    } else {\n        throw e;\n    }\n}","preventionTips":["Assign outBus through a single owner; don't mix dispose callbacks with direct reassignment.","Detach via outBus = null (or bus.disconnect) before routing to a new bus.","Check bus.isDisposed after any graph rebuild before reusing stale bus references.","Subscribe to the bus's onDisposeObservable to null out local references instead of relying on them later."],"tags":["audio","webaudio","bus","dispose","graph-state"],"backgroundTag":"audio-node-disconnect-failed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}