mrdoob/three.js · error · Error

THREE.BatchedMesh: Invalid instanceId ${instanceId}. Instanc

Error message

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

What it means

Thrown by BatchedMesh.validateInstanceId() when the instanceId is negative, greater than or equal to the instance info array length, or refers to a deleted (inactive) instance. Many BatchedMesh APIs call validateInstanceId internally, so passing a stale or out-of-range id triggers it.

Source

Thrown at src/objects/BatchedMesh.js:458

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

			}

		}

	}

	/**
	 * Validates the instance defined by the given ID.
	 *
	 * @param {number} instanceId - The instance to validate.
	 */
	validateInstanceId( instanceId ) {

		const instanceInfo = this._instanceInfo;
		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.` );

		}

View on GitHub (pinned to da05705fa3)

Solutions

  1. Track instance lifecycle: clear any cached id after deleteInstance() returns.
  2. Before using an id, call `batch.validateInstanceId(id)` in a try/catch, or bound-check against `batch.instanceCount` and track active ids yourself.
  3. Avoid shrinking maxInstanceCount below currently-used ids (setInstanceCount throws separately for that).

Example fix

// before
batch.deleteInstance( id );
batch.setMatrixAt( id, matrix ); // id now invalid

// after
batch.deleteInstance( id );
// stop referencing `id`; remove it from your id->object map
Defensive patterns

Strategy: validation

Validate before calling

function isValidInstanceId( batch, id ) {
  const info = batch._instanceInfo;
  return id >= 0 && id < info.length && info[ id ].active === true;
}

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

Type guard

const isActiveInstance = ( batch, id ) => isValidInstanceId( batch, id );

Try / catch

try {
  batch.getMatrixAt( id, matrix );
} catch ( e ) {
  if ( /Invalid instanceId/.test( e.message ) ) {
    // id was deleted or out of range; skip this entity
  } else throw e;
}

Prevention

When it happens

Trigger: Using an instanceId returned before a deleteInstance() call; caching an id across a setInstanceCount() shrink; passing an unvalidated index from user input; off-by-one when iterating instance ids.

Common situations: Caching instance ids in application data structures that outlive the instance; deleting instances and then referencing them; shrinking maxInstanceCount while ids above the new cap are still referenced.

Related errors


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