mrdoob/three.js · error · Error

THREE.BatchedMesh: Geometry index values are being used outs

Error message

THREE.BatchedMesh: Geometry index values are being used outside the range ${ maxIndexCount }. Cannot shrink further.

What it means

Thrown by BatchedMesh.setGeometrySize() when shrinking the INDEX buffer would cut into a reserved index range still in use. The condition is requiredIndexLength > maxIndexCount where requiredIndexLength is the max over active ranges of (indexStart + reservedIndexCount). Only checked when the batch geometry has an index attribute.

Source

Thrown at src/objects/BatchedMesh.js:1344

	*/
	setGeometrySize( maxVertexCount, maxIndexCount ) {

		// Check if we can shrink to the requested vertex attribute size
		const validRanges = [ ...this._geometryInfo ].filter( info => info.active );
		const requiredVertexLength = Math.max( ...validRanges.map( range => range.vertexStart + range.reservedVertexCount ) );
		if ( requiredVertexLength > maxVertexCount ) {

			throw new Error( `THREE.BatchedMesh: Geometry vertex values are being used outside the range ${ maxIndexCount }. Cannot shrink further.` );

		}

		// Check if we can shrink to the requested index attribute size
		if ( this.geometry.index ) {

			const requiredIndexLength = Math.max( ...validRanges.map( range => range.indexStart + range.reservedIndexCount ) );
			if ( requiredIndexLength > maxIndexCount ) {

				throw new Error( `THREE.BatchedMesh: Geometry index values are being used outside the range ${ maxIndexCount }. Cannot shrink further.` );

			}

		}

		//

		// dispose of the previous geometry
		const oldGeometry = this.geometry;
		oldGeometry.dispose();

		// recreate the geometry needed based on the previous variant
		this._maxVertexCount = maxVertexCount;
		this._maxIndexCount = maxIndexCount;

		if ( this._geometryInitialized ) {

			this._geometryInitialized = false;

View on GitHub (pinned to da05705fa3)

Solutions

  1. Compute Math.max(...activeRanges.map(r => r.indexStart + r.reservedIndexCount)) and pass a maxIndexCount at least that large.
  2. deleteGeometry on slots whose index reservations extend into the tail before shrinking.
  3. If the batch is non-indexed, this check is skipped — consider whether indexing is required.
  4. Re-allocate the BatchedMesh at the desired index capacity and migrate geometries if aggressive shrinking is needed.

Example fix

// before
batch.setGeometrySize( 10000, 500 ); // throws: indexed geometry needs more

// after
const requiredIndices = Math.max( ...batch.geometryInfo.filter(i=>i.active).map(i => i.indexStart + i.reservedIndexCount) );
batch.setGeometrySize( 10000, requiredIndices );
Defensive patterns

Strategy: validation

Validate before calling

const requiredIndices = Math.max(
  ...batchedMesh.geometryInfo.filter( i => i.active ).map( i => i.indexStart + i.reservedIndexCount )
);
if ( maxIndexCount >= requiredIndices ) batchedMesh.setGeometrySize( maxVertexCount, maxIndexCount );

Prevention

When it happens

Trigger: Calling batchedMesh.setGeometrySize(maxVertexCount, maxIndexCount) with maxIndexCount smaller than the highest indexStart + reservedIndexCount among active geometry slots, on an indexed batch.

Common situations: Compacting index memory after removing geometries but before their index reservations are released; lowering index capacity while indexed meshes still occupy the tail.

Related errors


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