{"record":{"id":"7f8d0f6fbf53cb1a","repo":"BabylonJS/Babylon.js","slug":"draco-failed-to-encode","errorCode":null,"errorMessage":"Draco: Failed to encode.","messagePattern":"Draco: Failed to encode\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Meshes/Compression/dracoCompressionWorker.ts","lineNumber":111,"sourceCode":"            attributeIDs[attribute.kind] = addAttribute(meshBuilder, mesh, encoderModule[attribute.dracoName], verticesCount, attribute.size, attribute.data);\r\n            if (options.quantizationBits && options.quantizationBits[attribute.dracoName]) {\r\n                encoder.SetAttributeQuantization(encoderModule[attribute.dracoName], options.quantizationBits[attribute.dracoName]);\r\n            }\r\n        }\r\n\r\n        // Set the options\r\n        if (options.method) {\r\n            encoder.SetEncodingMethod(encoderModule[options.method]);\r\n        }\r\n        if (options.encodeSpeed !== undefined && options.decodeSpeed !== undefined) {\r\n            encoder.SetSpeedOptions(options.encodeSpeed, options.decodeSpeed);\r\n        }\r\n\r\n        // Encode to native buffer\r\n        encodedNativeBuffer = new encoderModule.DracoInt8Array();\r\n        const encodedLength = encoder.EncodeMeshToDracoBuffer(mesh, encodedNativeBuffer);\r\n        if (encodedLength <= 0) {\r\n            throw new Error(\"Draco: Failed to encode.\");\r\n        }\r\n\r\n        // Copy the native buffer data to worker heap\r\n        const encodedData = new Int8Array(encodedLength);\r\n        for (let i = 0; i < encodedLength; i++) {\r\n            encodedData[i] = encodedNativeBuffer.GetValue(i);\r\n        }\r\n\r\n        return { data: encodedData, attributeIds: attributeIDs };\r\n    } finally {\r\n        if (mesh) {\r\n            encoderModule.destroy(mesh);\r\n        }\r\n        if (meshBuilder) {\r\n            encoderModule.destroy(meshBuilder);\r\n        }\r\n        if (encoder) {\r\n            encoderModule.destroy(encoder);\r","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Meshes/Compression/dracoCompressionWorker.ts#L93-L129","documentation":"After building the Draco mesh and encoder, EncodeMesh calls encoder.EncodeMeshToDracoBuffer and checks the returned length. A non-positive length means the native Draco encoder produced no output (encoding failed internally), so the worker throws this Error instead of returning an empty buffer.","triggerScenarios":"EncodeMeshToDracoBuffer returns <= 0, typically due to invalid/inconsistent attribute data (wrong buffer sizes vs point counts), corrupted indices, or unsupported option combinations passed through options.","commonSituations":"Manually assembling attribute data with mismatched vertex counts; index buffers referencing vertices beyond the position count; feeding NaN/degenerate data; rare Draco native-library failures on exotic attribute combinations.","solutions":["Validate that every attribute's data length matches numPoints * numComponents and indices are within range before encoding.","Simplify the options (e.g. drop quantization bits settings) to isolate which option breaks encoding.","Check that the Draco encoder module version matches the data/features used (e.g. position quantization support).","Log attribute sizes and index ranges and retry encoding after fixing the mesh data."],"exampleFix":"// before\nconst mesh = { attributes, indices: badIndices }; // indices reference vertex 999999\nencoder.EncodeMeshToDracoBuffer(mesh, out); // <= 0 -> throws\n\n// after\nconst maxIndex = Math.max(...indices);\nif (maxIndex >= positions.length / 3) {\n  indices = indices.filter((i) => i < positions.length / 3); // or fix mesh\n}\nconst encodedLength = encoder.EncodeMeshToDracoBuffer(mesh, out);","handlingStrategy":"validation","validationCode":"const numPoints = positions.length / 3;\nconst maxIndex = indices.reduce((m, i) => Math.max(m, i), 0);\nif (!Number.isFinite(numPoints) || numPoints === 0) throw new Error('empty position data');\nif (maxIndex >= numPoints) throw new Error('index out of range: ' + maxIndex);\nfor (const a of attributes) {\n  if (a.data.length !== numPoints * a.numComponents) throw new Error('attribute size mismatch: ' + a.kind);\n}","typeGuard":"const isEncodableMesh = (m: { attributes: any[]; indices: number[] }): boolean =>\n  m.attributes.every((a) => Array.isArray(a.data) || ArrayBuffer.isView(a.data)) &&\n  m.indices.every((i) => Number.isInteger(i) && i >= 0);","tryCatchPattern":"try {\n  return await encodeMeshAsync(attributes, indices, options);\n} catch (e) {\n  if (String(e?.message).includes('Failed to encode')) {\n    return await encodeMeshAsync(attributes, indices, { quantizationBits: undefined }); // retry without exotic options\n  }\n  throw e;\n}","preventionTips":["Assert attribute buffer sizes equal numPoints * numComponents before encoding.","Clamp/validate index buffers against the vertex count.","Avoid NaN/Infinity in vertex data; sanitize before encoding.","Pin a known-good Draco encoder module version in CI."],"tags":["draco","encoding","mesh","wasm"],"backgroundTag":"encoder-failed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}