BabylonJS/Babylon.js · error

${extensionContext}: Direction or Distance properties are no

Error message

${extensionContext}: Direction or Distance properties are not allowed on emitters attached to a scene

What it means

In MSFT_audio_emitter, emitters attached to a scene node may not use spatial parameters (source, outerAngle/innerAngle, rolloffFactor, distanceModel, maxDistance, direction or distance gain parameters) because scene-attached emitters have no positional context. When loadSceneAsync finds any of these properties set on a scene-level emitter, it throws to prevent invalid audio configuration.

Source

Thrown at packages/dev/loaders/src/glTF/2.0/Extensions/MSFT_audio_emitter.pure.ts:118

     */
    // eslint-disable-next-line no-restricted-syntax
    public loadSceneAsync(context: string, scene: IScene): Nullable<Promise<void>> {
        return GLTFLoader.LoadExtensionAsync<IMSFTAudioEmitter_EmittersReference>(context, scene, this.name, async (extensionContext, extension) => {
            const promises = new Array<Promise<any>>();

            promises.push(this._loader.loadSceneAsync(context, scene));

            for (const emitterIndex of extension.emitters) {
                const emitter = ArrayItem.Get(`${extensionContext}/emitters`, this._emitters, emitterIndex);
                if (
                    emitter.refDistance != undefined ||
                    emitter.maxDistance != undefined ||
                    emitter.rolloffFactor != undefined ||
                    emitter.distanceModel != undefined ||
                    emitter.innerAngle != undefined ||
                    emitter.outerAngle != undefined
                ) {
                    throw new Error(`${extensionContext}: Direction or Distance properties are not allowed on emitters attached to a scene`);
                }

                promises.push(this._loadEmitterAsync(`${extensionContext}/emitters/${emitter.index}`, emitter));
            }

            await Promise.all(promises);
        });
    }

    /**
     * @internal
     */
    // eslint-disable-next-line no-restricted-syntax
    public loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>> {
        return GLTFLoader.LoadExtensionAsync<IMSFTAudioEmitter_EmittersReference, TransformNode>(context, node, this.name, async (extensionContext, extension) => {
            const promises = new Array<Promise<any>>();

            const babylonMesh = await this._loader.loadNodeAsync(extensionContext, node, (babylonMesh) => {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Remove direction/distance/angle/rolloff/distanceModel properties from scene-level emitters in the glTF.
  2. Attach the emitter to a node instead if spatial audio behavior is intended.
  3. Keep only gain and playback properties on scene-attached (background) emitters.

Example fix

// before (scene emitter)
{ "index": 0, "innerAngle": 30, "outerAngle": 60 }
// after
{ "index": 0 }
Defensive patterns

Strategy: validation

Validate before calling

const spatial = ['direction','distance','innerAngle','outerAngle','rolloffFactor','distanceModel','maxDistance'];
const bad = sceneEmitter && Object.keys(sceneEmitter).some(k => spatial.includes(k));
if (bad) throw new Error('Scene-level audio emitter must not declare spatial properties');

Type guard

function isNonSpatialEmitter(e: any): boolean {
  return ['source','innerAngle','outerAngle','rolloffFactor','distanceModel','maxDistance','direction'].every(k => e?.[k] === undefined);
}

Try / catch

try { await loader.loadAsync(url); } catch (e) {
  if (e.message.includes('Direction or Distance properties')) {
    // fix asset: strip spatial props from scene emitters, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: Loading a glTF whose top-level extensions.MSFT_audio_emitter.emitters[] entries declare direction/distance/spatial fields (e.g. rolloffFactor, innerCone/outerCone angles, distanceModel, maxDistance, or gain with distance/directional values).

Common situations: Assets authored by tools that apply the same emitter object to both nodes and the scene; hand-written glTF where background audio emitters accidentally copy positional emitter settings.

Related errors


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