{"record":{"id":"04661c86943689c9","repo":"BabylonJS/Babylon.js","slug":"draco-missing-position-attribute-for-encoding","errorCode":null,"errorMessage":"Draco: Missing position attribute for encoding.","messagePattern":"Draco: Missing position attribute for encoding\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Meshes/Compression/dracoCompressionWorker.ts","lineNumber":51,"sourceCode":" * @internal\r\n */\r\nexport function EncodeMesh(\r\n    module: unknown /** EncoderModule */,\r\n    attributes: Array<IDracoAttributeData>,\r\n    indices: Nullable<Uint16Array | Uint32Array>,\r\n    options: IDracoEncoderOptions\r\n): IDracoEncodedMeshData {\r\n    const encoderModule = module as EncoderModule;\r\n    let encoder: Nullable<Encoder> = null;\r\n    let meshBuilder: Nullable<MeshBuilder> = null;\r\n    let mesh: Nullable<Mesh> = null;\r\n    let encodedNativeBuffer: Nullable<DracoInt8Array> = null;\r\n    const attributeIDs: Record<string, number> = {}; // Babylon kind -> Draco unique id\r\n\r\n    // Double-check that at least a position attribute is provided\r\n    const positionAttribute = attributes.find((a) => a.dracoName === \"POSITION\");\r\n    if (!positionAttribute) {\r\n        throw new Error(\"Draco: Missing position attribute for encoding.\");\r\n    }\r\n\r\n    // If no indices are provided, assume mesh is unindexed. Let's generate them, since Draco meshes require them.\r\n    // TODO: This may be the POINT_CLOUD case, but need to investigate. Should work for now-- just less efficient.\r\n    if (!indices) {\r\n        // Assume position attribute is the largest attribute.\r\n        const positionVerticesCount = positionAttribute.data.length / positionAttribute.size;\r\n        indices = new (positionVerticesCount > 65535 ? Uint32Array : Uint16Array)(positionVerticesCount);\r\n        for (let i = 0; i < positionVerticesCount; i++) {\r\n            indices[i] = i;\r\n        }\r\n    }\r\n\r\n    try {\r\n        encoder = new encoderModule.Encoder();\r\n        meshBuilder = new encoderModule.MeshBuilder();\r\n        mesh = new encoderModule.Mesh();\r\n\r","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Meshes/Compression/dracoCompressionWorker.ts#L33-L69","documentation":"EncodeMesh in the Draco encoder worker requires at least one attribute whose Draco name is 'POSITION' because Draco meshes are defined by their point positions. Before encoding it searches the supplied attribute list and throws this Error if none is found.","triggerScenarios":"Calling DracoEncoder encodeMesh (or the high-level _encodeAsync path) with an attributes array that lacks a VertexBuffer.PositionKind entry — e.g. encoding normals/UVs only, or passing a kind string other than 'position'.","commonSituations":"Compressing point clouds/mesh metadata without positions; building the attribute list programmatically and skipping the position buffer; passing attribute descriptors with wrong dracoName values.","solutions":["Include the position attribute in the attributes array with dracoName 'POSITION' (kind: VertexBuffer.PositionKind).","Verify each attribute's dracoName/kind mapping before calling encodeMesh.","If the source mesh truly has no positions, Draco encoding is inapplicable — store the data another way."],"exampleFix":"// before\nconst attributes = [{ kind: VertexBuffer.NormalKind, dracoName: 'NORMAL', data: normals }];\n\n// after\nconst attributes = [\n  { kind: VertexBuffer.PositionKind, dracoName: 'POSITION', data: positions },\n  { kind: VertexBuffer.NormalKind, dracoName: 'NORMAL', data: normals }\n];","handlingStrategy":"validation","validationCode":"const hasPosition = attributes.some((a) => a.dracoName === 'POSITION');\nif (!hasPosition) {\n  throw new Error('encodeMesh requires a position attribute (dracoName: POSITION)');\n}","typeGuard":"const hasPositionAttribute = (attrs: { dracoName: string }[]): attrs is [{ dracoName: 'POSITION' }, ...typeof attrs] =>\n  attrs.some((a) => a.dracoName === 'POSITION');","tryCatchPattern":"try {\n  const result = await encodeMeshAsync(attributes, indices, options);\n} catch (e) {\n  if (String(e?.message).includes('Missing position attribute')) {\n    attributes = [POSITION_ATTR, ...attributes];\n    return encodeMeshAsync(attributes, indices, options);\n  }\n  throw e;\n}","preventionTips":["Always build attribute lists starting with VertexBuffer.PositionKind / dracoName 'POSITION'.","Write a unit test asserting every encoded mesh includes a POSITION attribute.","When extracting attributes from a mesh programmatically, never filter out the position buffer."],"tags":["draco","encoding","mesh","validation"],"backgroundTag":"missing-required-attribute","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}