mrdoob/three.js · error · Error

THREE.BatchedMesh: Invalid geometryId ${geometryId}. Geometr

Error message

THREE.BatchedMesh: Invalid geometryId ${geometryId}. Geometry is either out of range or has been deleted.

What it means

Thrown by BatchedMesh.validateGeometryId() when the geometryId is negative, greater than or equal to the geometry info list length, or refers to a deleted (inactive) geometry. APIs like addInstance(geometryId) validate the geometry id first.

Source

Thrown at src/objects/BatchedMesh.js:474

		if ( instanceId < 0 || instanceId >= instanceInfo.length || instanceInfo[ instanceId ].active === false ) {

			throw new Error( `THREE.BatchedMesh: Invalid instanceId ${instanceId}. Instance is either out of range or has been deleted.` );

		}

	}

	/**
	 * Validates the geometry defined by the given ID.
	 *
	 * @param {number} geometryId - The geometry to validate.
	 */
	validateGeometryId( geometryId ) {

		const geometryInfoList = this._geometryInfo;
		if ( geometryId < 0 || geometryId >= geometryInfoList.length || geometryInfoList[ geometryId ].active === false ) {

			throw new Error( `THREE.BatchedMesh: Invalid geometryId ${geometryId}. Geometry is either out of range or has been deleted.` );

		}

	}

	/**
	 * Takes a sort a function that is run before render. The function takes a list of instances to
	 * sort and a camera. The objects in the list include a "z" field to perform a depth-ordered sort with.
	 *
	 * @param {Function} func - The custom sort function.
	 * @return {BatchedMesh} A reference to this batched mesh.
	 */
	setCustomSort( func ) {

		this.customSort = func;
		return this;

	}

View on GitHub (pinned to da05705fa3)

Solutions

  1. Use only the id returned by addGeometry(); do not assume ids are contiguous after deletions.
  2. Invalidate cached geometry ids when the corresponding geometry is deleted.
  3. Bound-check the id against the geometry count and track active ids in your own map.

Example fix

// before
batch.deleteGeometry( geometryId );
batch.addInstance( geometryId ); // geometryId now invalid

// after
batch.deleteGeometry( geometryId );
// remove geometryId from your lookup; re-add geometry if still needed
Defensive patterns

Strategy: validation

Validate before calling

function isValidGeometryId( batch, id ) {
  const list = batch._geometryInfo;
  return id >= 0 && id < list.length && list[ id ].active === true;
}

if ( ! isValidGeometryId( batch, id ) ) throw new RangeError( `Invalid geometryId ${ id }` );

Type guard

const isActiveGeometry = ( batch, id ) => isValidGeometryId( batch, id );

Try / catch

try {
  batch.addInstance( geometryId );
} catch ( e ) {
  if ( /Invalid geometryId/.test( e.message ) ) {
    // geometry was deleted; re-add or skip
  } else throw e;
}

Prevention

When it happens

Trigger: Using a geometryId returned before deleteGeometry() was called; passing a geometry index that was never added; referencing a geometry id across a repack/optimize that invalidated it; off-by-one indexing.

Common situations: Caching geometry ids across geometry deletion/re-addition; assuming ids are contiguous after deletion; passing the index into a user array instead of the BatchedMesh-returned geometryId.

Related errors


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