BabylonJS/Babylon.js · error · Error
Draco: Encoder module is not available.
Error message
Draco: Encoder module is not available.
What it means
Inside the encoder worker, an 'encodeMesh' message can only be handled after the 'init' message has created the encoderPromise (the loaded Draco encoder module). If an encodeMesh request arrives before initialization, the worker throws this Error because there is no module to encode with.
Source
Thrown at packages/dev/core/src/Meshes/Compression/dracoCompressionWorker.ts:159
export function EncoderWorkerFunction(): void {
let encoderPromise: Promise<EncoderModule> | undefined;
onmessage = (event) => {
const message = event.data;
switch (message.id) {
case "init": {
// if URL is provided then load the script. Otherwise expect the script to be loaded already
if (message.url) {
importScripts(message.url);
}
const initEncoderObject = message.wasmBinary ? { wasmBinary: message.wasmBinary } : {};
encoderPromise = DracoEncoderModule(initEncoderObject);
postMessage({ id: "initDone" });
break;
}
case "encodeMesh": {
if (!encoderPromise) {
throw new Error("Draco: Encoder module is not available.");
}
encoderPromise
// eslint-disable-next-line github/no-then
.then((encoder) => {
const result = EncodeMesh(encoder, message.attributes, message.indices, message.options);
postMessage({ id: "encodeMeshSuccess", encodedMeshData: result }, result ? [result.data.buffer] : undefined);
})
// eslint-disable-next-line github/no-then
.catch((error) => {
postMessage({ id: "encodeMeshError", errorMessage: error.message });
});
break;
}
}
};
}
/**
View on GitHub (pinned to 0592b347b8)
Solutions
- Always send the 'init' message with the Draco encoder module/URL first and wait for the 'initDone' reply before sending 'encodeMesh'.
- Queue encodeMesh requests until initDone is received rather than posting them immediately.
- If init failed, re-create the worker and retry the init handshake instead of reusing the stale worker.
Example fix
// before
worker.postMessage({ id: 'encodeMesh', attributes, indices }); // init not sent
// after
worker.onmessage = (m) => {
if (m.data.id === 'initDone') worker.postMessage({ id: 'encodeMesh', attributes, indices, options });
};
worker.postMessage({ id: 'init', moduleConfig }); Defensive patterns
Strategy: retry
Validate before calling
if (!encoderWorkerReady) {
throw new Error('encoder worker not initialized: wait for initDone before encodeMesh');
} Type guard
const isWorkerReady = (w: { ready: boolean }): w is { ready: true } => w.ready === true; Try / catch
try {
return await sendEncodeRequest(message);
} catch (e) {
if (String(e?.message).includes('Encoder module is not available')) {
await initEncoderWorker(); // resend 'init', await 'initDone'
return await sendEncodeRequest(message);
}
throw e;
} Prevention
- Gate encodeMesh sends behind the worker's 'initDone' postMessage.
- Queue or buffer encode requests issued before init completes.
- Treat a failed init as fatal for the worker: recreate it rather than reusing.
- Add an integration test covering the init -> encode handshake ordering.
When it happens
Trigger: Posting an 'encodeMesh' message to the Draco encoder worker without first posting 'init' (or before init completes), e.g. a race where encode is called immediately after worker creation or after a failed init.
Common situations: Custom worker plumbing that skips the init handshake; calling encode before the encoder module (WASM) finished loading on slow networks; reusing a worker whose init message failed silently.
Related errors
- Recast is not initialized. Please call InitRecast first.
- Unable to generate navMesh: ${e}
- Draco: Decoder module is not available
- At least one mesh is needed to create the nav mesh.
- Unable to generate navMesh/tileCache: ${e}
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/5d5f93db48368ef1.
Report an issue: GitHub.