mrdoob/three.js · error · Error

THREE.BatchedMesh: All geometries must consistently have "in

Error message

THREE.BatchedMesh: All geometries must consistently have "index".

What it means

Thrown by BatchedMesh._validateGeometry() when the added geometry's indexed/non-indexed status differs from the batch's combined geometry. The check is `Boolean(geometry.getIndex()) !== Boolean(batchGeometry.getIndex())` — all geometries in a batch must consistently use an index buffer or consistently omit one.

Source

Thrown at src/objects/BatchedMesh.js:424

				geometry.setIndex( new BufferAttribute( indexArray, 1 ) );

			}

			this._geometryInitialized = true;

		}

	}

	// Make sure the geometry is compatible with the existing combined geometry attributes
	_validateGeometry( geometry ) {

		// check to ensure the geometries are using consistent attributes and indices
		const batchGeometry = this.geometry;
		if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {

			throw new Error( 'THREE.BatchedMesh: All geometries must consistently have "index".' );

		}

		for ( const attributeName in batchGeometry.attributes ) {

			if ( ! geometry.hasAttribute( attributeName ) ) {

				throw new Error( `THREE.BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` );

			}

			const srcAttribute = geometry.getAttribute( attributeName );
			const dstAttribute = batchGeometry.getAttribute( attributeName );
			if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) {

				throw new Error( 'THREE.BatchedMesh: All attributes must have a consistent itemSize and normalized value.' );

			}

View on GitHub (pinned to da05705fa3)

Solutions

  1. Make all geometries consistent: call `.toNonIndexed()` on every indexed geometry, or call `.setIndex()` to index every non-indexed one.
  2. Decide the batch's convention with the first addGeometry call, then ensure every subsequent geometry matches.
  3. Group indexed and non-indexed geometries into separate BatchedMesh instances.

Example fix

// before
batch.addGeometry( indexedBox );
batch.addGeometry( nonIndexedGeom );

// after
batch.addGeometry( indexedBox );
batch.addGeometry( nonIndexedGeom.toNonIndexed ? nonIndexedGeom : nonIndexedGeom );
// or normalize all to indexed/non-indexed before adding
Defensive patterns

Strategy: validation

Validate before calling

function assertCompatibleIndexing( batch, geometry ) {
  if ( Boolean( geometry.getIndex() ) !== Boolean( batch.geometry.getIndex() ) ) {
    throw new Error( 'Geometry indexing does not match the batch.' );
  }
}

Type guard

const matchesBatchIndexing = ( batch, geometry ) => Boolean( geometry.getIndex() ) === Boolean( batch.geometry.getIndex() );

Prevention

When it happens

Trigger: Mixing indexed geometries (e.g. BoxGeometry, PlaneGeometry) with non-indexed ones (e.g. some custom BufferGeometries) in the same BatchedMesh; adding a geometry after calling addGeometry with a differently-indexed first geometry.

Common situations: Batching a heterogeneous set of geometries; loading geometries from different loaders where some are indexed and some are not; converting a geometry to non-indexed (`geometry.toNonIndexed()`) for some but not all batch members.

Related errors


AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12). Data as JSON: /api/errors/8bc41fa2b38a4344. Report an issue: GitHub.