BabylonJS/Babylon.js · error · Error

Draco: Decoder module is not available

Error message

Draco: Decoder module is not available

What it means

In the Draco decoder worker, a "decodeMesh" message was received but no decoder module was ever initialized: `decoderPromise` is null. The worker requires an "init" message (which calls DracoDecoderModule) before any decode request. The library throws to prevent decoding with an uninitialized WASM decoder.

Source

Thrown at packages/dev/core/src/Meshes/Compression/dracoCompressionWorker.ts:338

export function DecoderWorkerFunction(): void {
    let decoderPromise: PromiseLike<DecoderModule> | 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 initDecoderObject = message.wasmBinary ? { wasmBinary: message.wasmBinary } : {};
                decoderPromise = DracoDecoderModule(initDecoderObject);
                postMessage({ id: "initDone" });
                break;
            }
            case "decodeMesh": {
                if (!decoderPromise) {
                    throw new Error("Draco: Decoder module is not available");
                }
                // eslint-disable-next-line github/no-then
                decoderPromise.then((decoder) => {
                    const numPoints = DecodeMesh(
                        decoder,
                        message.dataView,
                        message.attributes,
                        (indices) => {
                            postMessage({ id: "indices", data: indices }, [indices.buffer]);
                        },
                        (kind, data, size, offset, stride, normalized) => {
                            postMessage({ id: "attribute", kind, data, size, byteOffset: offset, byteStride: stride, normalized }, [data.buffer]);
                        }
                    );
                    postMessage({ id: "decodeMeshDone", totalVertices: numPoints });
                });
                break;
            }

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Ensure the Draco decoder is configured before decoding: set `dracoCompression.Configuration.decoder = { url: ... }` (or use default CDN) and await initialization (`DracoCompression.Default...` ready) prior to `_loadGroundAsync`/decode calls.
  2. Verify the decoder URL is reachable (network tab) and CORS/CSP allows the WASM script and .wasm fetch.
  3. Check that the worker receives the init message before decodeMesh; avoid manually posting worker messages out of order.
  4. Catch the worker error and re-queue the decode after re-initializing the decoder module.

Example fix

// before
mesh.convertToFlatShadedMesh();
DracoCompression.DecodeMeshToMeshDataAsync(data);

// after
DracoCompression.Configuration.decoder = { url: "https://cdn.babylonjs.com/draco/draco_decoder.js" };
await DracoCompression._GetDefaultSupported... // or simply await scene.whenReadyAsync();
const meshData = await DracoCompression.DecodeMeshToMeshDataAsync(data);
Defensive patterns

Strategy: validation

Validate before calling

if (!DracoCompression.Configuration.decoder?.available) {
    // load decoder config / await initialization before posting decodeMesh
    throw new SkipDecode();
}

Type guard

function decoderReady(): boolean {
    return !!DracoCompression.Configuration.decoder?.available;
}

Try / catch

try {
    await worker.decode(view);
} catch (e) {
    if (String(e?.message).includes("Decoder module is not available")) {
        await initDecoder();
        return worker.decode(view); // retry once after init
    }
    throw e;
}

Prevention

When it happens

Trigger: Posting a {type:"decodeMesh"} message to the Draco worker before posting the {type:"init"} message, or after init failed silently; also calling DracoCompressionWorker decode paths when the decoder configuration promise never resolved.

Common situations: Draco decoder URL misconfigured or blocked (CDN offline, CSP), CustomEXTRA headers/CORS preventing the WASM/JS module load, calling mesh conversion before `dracoCompression.Configuration` with `decoder.available` true, or racing multiple workers where the decode lands in a not-yet-initialized worker.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/ee9c4835a394e2c2. Report an issue: GitHub.