{"record":{"id":"5b972f2735626f9c","repo":"BabylonJS/Babylon.js","slug":"no-volume-subnode","errorCode":null,"errorMessage":"No volume subnode","messagePattern":"No volume subnode","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/AudioV2/abstractAudio/abstractAudioOutNode.ts","lineNumber":43,"sourceCode":"    /**\n     * The audio analyzer features.\n     */\n    public get analyzer(): AbstractAudioAnalyzer {\n        return this._analyzer ?? (this._analyzer = new _AudioAnalyzer(this._subGraph));\n    }\n\n    /**\n     * The audio output volume.\n     */\n    public get volume(): number {\n        return _GetVolumeAudioProperty(this._subGraph, \"volume\");\n    }\n\n    public set volume(value: number) {\n        // The volume subnode is created on initialization and should always exist.\n        const node = _GetVolumeAudioSubNode(this._subGraph);\n        if (!node) {\n            throw new Error(\"No volume subnode\");\n        }\n\n        node.volume = value;\n    }\n\n    /**\n     * Releases associated resources.\n     */\n    public override dispose(): void {\n        super.dispose();\n\n        this._analyzer?.dispose();\n        this._analyzer = null;\n\n        this._subGraph.dispose();\n    }\n\n    /**","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/AudioV2/abstractAudio/abstractAudioOutNode.ts#L25-L61","documentation":"The volume setter on AbstractAudioOutNode (implemented by sounds, sound sources, and buses in Babylon.js Audio V2) assumes a volume audio subnode was created when the node was initialized, as the in-code comment states. _GetVolumeAudioSubNode(this._subGraph) returned null, so assigning node.volume throws \"No volume subnode\". This means the node's sub-graph was never initialized or has already been disposed.","triggerScenarios":"Setting `node.volume = x` on an audio node whose _subGraph has no volume subnode — typically after calling dispose() on the node, before async initialization of the subgraph completed, or if the subgraph failed to create its subnodes (e.g. audio engine/context not ready).","commonSituations":"Setting volume after sound.dispose() in a UI callback firing late; setting volume immediately after construction before the sound's internal async creation promise resolves; engine shutdown or context loss tearing down subnodes while app code still holds the node reference.","solutions":["Wait for node readiness before setting volume — e.g. use the async creation API (await SoundV2.CreateAsync / engine.createSoundAsync) so the subgraph and its volume subnode exist.","Check that the node has not been disposed; do not touch volume after calling dispose() or after the engine is released.","Verify the Web Audio context/engine is still running; a suspended/closed engine can prevent subnode creation.","If you cannot guarantee timing, wrap the assignment in try/catch and treat \"No volume subnode\" as 'node not ready or disposed'."],"exampleFix":"// before\nconst sound = await engine.createSoundAsync(url);\nsound.dispose();\nsound.volume = 0.5; // throws\n\n// after\nconst sound = await engine.createSoundAsync(url);\nif (!sound.isDisposed) {\n    sound.volume = 0.5;\n}","handlingStrategy":"try-catch","validationCode":"// set volume only when the node is ready and not disposed\nif (!sound.isDisposed && engine.state === \"Started\") {\n    sound.volume = 0.5;\n}","typeGuard":"function canSetVolume(node) {\n    return node != null && !node.isDisposed && typeof node.volume === \"number\";\n}","tryCatchPattern":"try {\n    sound.volume = 0.5;\n} catch (e) {\n    if (e.message === \"No volume subnode\") {\n        // node not initialized or already disposed; retry after ready or skip\n    } else {\n        throw e;\n    }\n}","preventionTips":["Await async creation APIs (createSoundAsync / CreateAsync) before touching volume.","Null out UI bindings, timers, and animation callbacks when the node is disposed.","Check engine/context state after tab suspension or user-gesture resume before setting volume.","Treat any post-dispose access as a bug: guard all writes with an isDisposed check."],"tags":["audio","webaudio","volume","lifecycle"],"backgroundTag":"missing-audio-subnode","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}