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

  1. Add a "POSITION" entry to the primitive's attributes pointing at a valid VEC3 float accessor
  2. Re-export the asset from the source tool ensuring positions are written
  3. 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

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


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