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
- Remove direction/distance/angle/rolloff/distanceModel properties from scene-level emitters in the glTF.
- Attach the emitter to a node instead if spatial audio behavior is intended.
- 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
- Keep spatial properties only on node-attached emitters.
- Add asset validation that separates background (scene) emitters from positional ones.
- Avoid sharing emitter objects between scene and node contexts in authoring tools.
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
- ${context}: Unsupported action ${action}
- The value passed to [Scene.audioListenerPositionProvider] mu
- The value passed to [Scene.audioListenerRotationProvider] mu
- Sounds length does not equal weights length
- ${extensionContext}/attributes: Instance buffer accessors do
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/e9fc43a5a71baec0.
Report an issue: GitHub.