BabylonJS/Babylon.js · error · Error
${extensionContext}: Gaussian splatting primitive is missing
Error message
${extensionContext}: Gaussian splatting primitive is missing the POSITION attribute What it means
A KHR_gaussian_splatting primitive must supply a POSITION attribute (the splat center positions). The loader looks up primitive.attributes["POSITION"] and throws when no accessor is bound for it, because the splat renderer cannot place points without positions.
Source
Thrown at packages/dev/loaders/src/glTF/2.0/Extensions/KHR_gaussian_splatting.pure.ts:91
return GLTFLoader.LoadExtensionAsync<IKHRGaussianSplatting, AbstractMesh>(context, primitive, this.name, async (extensionContext) => {
if (primitive.mode != undefined && primitive.mode !== MeshPrimitiveMode.POINTS) {
throw new Error(`${extensionContext}: Gaussian splatting primitives must use POINTS mode`);
}
const loader = this._loader;
const loadAttribute = (attributeName: string): Nullable<Promise<Float32Array>> => {
const accessorIndex = primitive.attributes[attributeName];
if (accessorIndex == undefined) {
return null;
}
const accessor = ArrayItem.Get(`${context}/attributes/${attributeName}`, loader.gltf.accessors, accessorIndex) as IAccessor;
return loader._loadFloatAccessorAsync(`/accessors/${accessor.index}`, accessor);
};
const positionsPromise = loadAttribute("POSITION");
if (!positionsPromise) {
throw new Error(`${extensionContext}: Gaussian splatting primitive is missing the POSITION attribute`);
}
// Determine which spherical harmonics degrees are present (all lower degrees must exist per spec).
let shDegree = 0;
const shAttributeNames: string[] = [];
for (let degree = 1; degree <= 3; degree++) {
if (primitive.attributes[`KHR_gaussian_splatting:SH_DEGREE_${degree}_COEF_0`] == undefined) {
break;
}
shDegree = degree;
for (let coef = 0; coef < ShCoefficientCountPerDegree[degree]; coef++) {
shAttributeNames.push(`KHR_gaussian_splatting:SH_DEGREE_${degree}_COEF_${coef}`);
}
}
// Create the Gaussian Splatting mesh and assign it to the node synchronously (before awaiting the
// attribute data). The base loader wires the node's transform node from this assign call
// synchronously, so it must happen before the first await. The splat data is uploaded afterwards.
View on GitHub (pinned to 0592b347b8)
Solutions
- Add a "POSITION" entry to the primitive's attributes pointing at a valid VEC3 float accessor
- Re-export the asset from the source tool ensuring positions are written
- Validate the asset with a glTF validator before loading
Example fix
// before
"attributes": { "scale_0": 1, "rotation_0": 2 }
// after
"attributes": { "POSITION": 5, "scale_0": 1, "rotation_0": 2 } Defensive patterns
Strategy: validation
Validate before calling
function hasPosition(p) {
return typeof p.attributes?.POSITION === "number";
}
// check every gaussian-splatting primitive has attributes.POSITION before loading Type guard
const hasPositionAttribute = (p: { attributes?: Record<string, number> }): p is { attributes: Record<string, number> & { POSITION: number } } => typeof p.attributes?.POSITION === "number"; Try / catch
try {
await loader.loadAsync(url);
} catch (e) {
if (e instanceof Error && e.message.includes("missing the POSITION attribute")) {
console.error("Splat primitive lacks POSITION; regenerate the asset.");
} else throw e;
} Prevention
- Never strip the POSITION accessor when optimizing splat assets
- Validate glTF assets (attributes completeness) before shipping
- Re-export assets after editing primitive attributes manually
When it happens
Trigger: Loading a glTF asset whose gaussian-splatting primitive's 'attributes' object lacks a "POSITION" entry, or whose POSITION index points outside the accessors array so loadAttribute returns nothing.
Common situations: Hand-authored or minimally-generated glTF that lists splat SH/opacity attributes but forgot POSITION; an exporter bug dropping the POSITION accessor; stripping accessors during asset optimization and removing POSITION.
Related errors
- ${extensionContext}: Gaussian splatting primitives must use
- Buffer access is out of range
- ${extensionContext}: Invalid area light type (${light.type})
- ${context}: Irradiance coefficients are missing
- ${extensionContext}/attributes: Instance buffer accessors do
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/2120c10fa0c228d9.
Report an issue: GitHub.