mrdoob/three.js · error · TypeError

THREE.BufferAttribute: array should be a Typed Array.

Error message

THREE.BufferAttribute: array should be a Typed Array.

What it means

The BufferAttribute constructor throws a TypeError when its first argument is a plain JavaScript Array. BufferAttribute requires a TypedArray (e.g. Float32Array, Uint16Array) because GPU buffers need contiguous, fixed-width binary data; a regular Array is a boxed, heterogeneous JS object and cannot be uploaded to the GPU.

Source

Thrown at src/core/BufferAttribute.js:36

 * When working with vector-like data, the `fromBufferAttribute( attribute, index )`
 * helper methods on vector and color class might be helpful. E.g. {@link Vector3#fromBufferAttribute}.
 */
class BufferAttribute extends EventDispatcher {

	/**
	 * Constructs a new buffer attribute.
	 *
	 * @param {TypedArray} array - The array holding the attribute data.
	 * @param {number} itemSize - The item size.
	 * @param {boolean} [normalized=false] - Whether the data are normalized or not.
	 */
	constructor( array, itemSize, normalized = false ) {

		super();

		if ( Array.isArray( array ) ) {

			throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );

		}

		/**
		 * This flag can be used for type testing.
		 *
		 * @type {boolean}
		 * @readonly
		 * @default true
		 */
		this.isBufferAttribute = true;

		/**
		 * The ID of the buffer attribute.
		 *
		 * @name BufferAttribute#id
		 * @type {number}
		 * @readonly

View on GitHub (pinned to da05705fa3)

Solutions

  1. Wrap the array in a TypedArray matching your data type, e.g. new Float32Array([...]) for positions/normals/uv, new Uint16Array or Uint32Array for indices.
  2. Use the typed convenience constructors: new THREE.Float32BufferAttribute(array, itemSize) or Uint16/Uint32/Int8 equivalents, which accept a plain array and convert it for you.
  3. When parsing external data, convert once: const typed = new Float32Array(parsedArray) before creating the attribute.
  4. Confirm itemSize matches the component count (2 for uv, 3 for position/normal) so the TypedArray length is itemSize * vertexCount.

Example fix

// before
const attr = new THREE.BufferAttribute([0,0,0, 1,0,0], 3); // throws TypeError

// after
const attr = new THREE.BufferAttribute(new Float32Array([0,0,0, 1,0,0]), 3);
// or use the convenience subclass that accepts a plain array
const attr2 = new THREE.Float32BufferAttribute([0,0,0, 1,0,0], 3);
Defensive patterns

Strategy: type-guard

Validate before calling

function toTypedArray(array, Ctor = Float32Array) {
  if (ArrayBuffer.isView(array) && !Array.isArray(array)) return array;
  if (Array.isArray(array)) return new Ctor(array);
  throw new TypeError('Expected a TypedArray or plain array');
}

const attr = new THREE.BufferAttribute(toTypedArray(data), itemSize);

Type guard

function isTypedArray(value) {
  return value != null
    && typeof value === 'object'
    && ArrayBuffer.isView(value)
    && !(value instanceof DataView);
}

// usage
if (!isTypedArray(array)) array = new Float32Array(array);

Prevention

When it happens

Trigger: Constructing new THREE.BufferAttribute([x, y, z, ...], itemSize) with a literal array or an array built via [].push(). Also wrapping data produced by JSON.parse or CSV parsing (which yield normal Arrays) without converting to a TypedArray.

Common situations: Beginners building geometry from hand-written coordinate lists. Loading numeric data from JSON/text and passing it straight to geometry.setAttribute(). Porting code from libraries that return plain arrays. Using BufferAttribute where a Float32BufferAttribute convenience subclass was intended.

Related errors


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