{"record":{"id":"2409544f80610010","repo":"mrdoob/three.js","slug":"three-webgpuattributeutils-bad-vertex-format-item","errorCode":null,"errorMessage":"THREE.WebGPUAttributeUtils: Bad vertex format item size.","messagePattern":"THREE\\.WebGPUAttributeUtils: Bad vertex format item size\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderers/webgpu/utils/WebGPUAttributeUtils.js","lineNumber":535,"sourceCode":"\n\t\tif ( itemSize === 1 ) {\n\n\t\t\tformat = typeArraysToVertexFormatPrefixForItemSize1.get( ArrayType );\n\n\t\t} else {\n\n\t\t\tconst prefixOptions = typedAttributeToVertexFormatPrefix.get( AttributeType ) || typedArraysToVertexFormatPrefix.get( ArrayType );\n\t\t\tconst prefix = prefixOptions[ normalized ? 1 : 0 ];\n\n\t\t\tif ( prefix ) {\n\n\t\t\t\tconst bytesPerUnit = ArrayType.BYTES_PER_ELEMENT * itemSize;\n\t\t\t\tconst paddedBytesPerUnit = Math.floor( ( bytesPerUnit + 3 ) / 4 ) * 4;\n\t\t\t\tconst paddedItemSize = paddedBytesPerUnit / ArrayType.BYTES_PER_ELEMENT;\n\n\t\t\t\tif ( paddedItemSize % 1 ) {\n\n\t\t\t\t\tthrow new Error( 'THREE.WebGPUAttributeUtils: Bad vertex format item size.' );\n\n\t\t\t\t}\n\n\t\t\t\tformat = `${prefix}x${paddedItemSize}`;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( ! format ) {\n\n\t\t\terror( 'WebGPUAttributeUtils: Vertex format not supported yet.' );\n\n\t\t}\n\n\t\treturn format;\n\n\t}","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/mrdoob/three.js/blob/da05705fa31f02710c19772a2aa70c7454807f0c/src/renderers/webgpu/utils/WebGPUAttributeUtils.js#L517-L553","documentation":"Thrown by WebGPUAttributeUtils._getVertexFormat while deriving a WebGPU vertex format string ('prefix x N') for a BufferAttribute with itemSize > 1. It computes bytesPerUnit = elementByteSize * itemSize, rounds it up to a 4-byte WebGPU alignment boundary (paddedBytesPerUnit), then requires paddedBytesPerUnit / ArrayType.BYTES_PER_ELEMENT to be a whole number. If that quotient is fractional, no valid WebGPU vertex format can describe the attribute, so construction is rejected. With the standard typed arrays registered in typedArraysToVertexFormatPrefix (element sizes 1, 2, or 4 bytes), the padded value is always divisible, so this guard is a defensive invariant that fires only for unusual element sizes or a custom BufferAttribute subclass whose backing array does not evenly divide a 4-byte boundary.","triggerScenarios":"Registering a custom BufferAttribute subclass in typedAttributeToVertexFormatPrefix backed by a non-standard typed array (element size not in {1,2,4}) combined with an itemSize that makes the 4-byte-padded byte count indivisible by the element size. Monkey-patching or extending BufferAttribute with an array whose .constructor reports a typed array whose BYTES_PER_ELEMENT does not divide 4. Theoretically also with engineered itemSize values, though standard 1/2/4-byte arrays make the division always integral.","commonSituations":"Using a custom or polyfilled typed array (e.g. BigInt64Array/BigUint64Array with 8-byte elements, or a shim reporting a non-standard byte size) for a vertex attribute. Porting WebGL code that used exotic packed formats. Library upgrades where a previously-tolerated custom attribute type is now routed through _getVertexFormat via the prefix maps.","solutions":["Back the attribute with one of the supported standard typed arrays (Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float16Array) so paddedBytesPerUnit is always divisible.","Use an itemSize in {1,2,3,4} which is what the WebGPU vertex-format table covers for these element sizes.","If a non-standard packed layout is genuinely required, interleave the data into a Float32Array/Uint8Array attribute with a matching itemSize and decode in the shader instead.","Remove any custom entry you added to typedAttributeToVertexFormatPrefix/typedArraysToVertexFormatPrefix unless the backing array reports a BYTES_PER_ELEMENT in {1,2,4}."],"exampleFix":"// before: custom typed array with non power-of-two friendly element size\nclass WeirdArray extends Array { static get BYTES_PER_ELEMENT(){ return 3; } }\ngeo.setAttribute( 'position', new THREE.BufferAttribute( new WeirdArray( data ), 2 ) ); // throws\n\n// after: use a standard typed array sized to the 4-byte WebGPU vertex alignment\ngeo.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( data ), 3 ) );","handlingStrategy":"validation","validationCode":"const SUPPORTED_VERTEX_ARRAY_TYPES = new Set( [\n  Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array,\n  ...( typeof Float16Array !== 'undefined' ? [ Float16Array ] : [] ),\n] );\n\n// Reject before attaching an attribute whose WebGPU vertex format cannot be derived.\nfunction isWebGPUVertexAttributeOk( attribute ) {\n  const { itemSize, array } = attribute;\n  if ( ! SUPPORTED_VERTEX_ARRAY_TYPES.has( array.constructor ) ) return false;\n  if ( itemSize < 1 || itemSize > 4 ) return false;\n  const bytesPerUnit = array.constructor.BYTES_PER_ELEMENT * itemSize;\n  const padded = Math.floor( ( bytesPerUnit + 3 ) / 4 ) * 4;\n  return Number.isInteger( padded / array.constructor.BYTES_PER_ELEMENT );\n}\n\nif ( ! isWebGPUVertexAttributeOk( attr ) ) {\n  throw new Error( 'Attribute would produce a bad WebGPU vertex format' );\n}","typeGuard":"function isStandardVertexAttribute( attribute ) {\n  const ArrayCtor = attribute?.array?.constructor;\n  const supported = [ Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array ];\n  if ( typeof Float16Array !== 'undefined' ) supported.push( Float16Array );\n  return supported.includes( ArrayCtor ) && [ 1, 2, 3, 4 ].includes( attribute.itemSize );\n}","tryCatchPattern":null,"preventionTips":["Only attach BufferAttributes backed by standard 1/2/4-byte typed arrays to geometries rendered with WebGPU.","Keep itemSize in the 1-4 range that maps onto the WebGPU vertex-format table.","Do not extend typedArraysToVertexFormatPrefix / typedAttributeToVertexFormatPrefix with arrays whose BYTES_PER_ELEMENT is not 1, 2, or 4.","Validate attributes once at scene-load time rather than discovering the failure during rendering."],"tags":["webgpu","vertex-format","buffer-attribute","geometry"],"backgroundTag":null,"analyzedSha":"da05705fa31f02710c19772a2aa70c7454807f0c","analyzedAt":"2026-08-12T22:51:37.160Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}