BabylonJS/Babylon.js · error

deflate: invalid distance symbol

Error message

deflate: invalid distance symbol

What it means

Distance symbols are valid in 0-29 in deflate. This error fires when distanceTree.decode returns a value above 29 (possible only with a fixed distance tree's 32-symbol space), i.e. the stream encoded an out-of-range distance code — the data is corrupt or being decoded with the wrong tree.

Source

Thrown at packages/dev/loaders/src/FBX/parsers/zlibInflate.ts:329

function inflateCompressedBlock(reader: BitReader, output: OutputWriter, literalLengthTree: HuffmanTree, distanceTree: HuffmanTree): void {
    while (true) {
        const symbol = literalLengthTree.decode(reader);
        if (symbol < 256) {
            output.writeByte(symbol);
            continue;
        }
        if (symbol === 256) {
            return;
        }
        if (symbol > 285) {
            throw new Error("deflate: invalid literal/length symbol");
        }

        const lengthIndex = symbol - 257;
        const length = LENGTH_BASE[lengthIndex] + reader.readBits(LENGTH_EXTRA_BITS[lengthIndex]);
        const distanceSymbol = distanceTree.decode(reader);
        if (distanceSymbol > 29) {
            throw new Error("deflate: invalid distance symbol");
        }
        const distance = DISTANCE_BASE[distanceSymbol] + reader.readBits(DISTANCE_EXTRA_BITS[distanceSymbol]);
        output.copy(distance, length);
    }
}

function readDynamicTrees(reader: BitReader): {
    literalLengthTree: HuffmanTree;
    distanceTree: HuffmanTree;
} {
    const literalLengthCount = reader.readBits(5) + 257;
    const distanceCount = reader.readBits(5) + 1;
    const codeLengthCount = reader.readBits(4) + 4;

    const codeLengthLengths = new Array<number>(19).fill(0);
    for (let i = 0; i < codeLengthCount; i++) {
        codeLengthLengths[CODE_LENGTH_ORDER[i]] = reader.readBits(3);
    }

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Confirm with python zlib.decompress(payload) whether the payload is genuinely valid zlib — most often the file is corrupt
  2. Verify the payload slice boundaries against the FBX array header's compressed byte count
  3. Re-export/re-download the FBX asset
  4. If reproducing from a specific file, dump the payload bytes around the failure offset to inspect whether it resembles compressed data at all
Defensive patterns

Strategy: try-catch

Validate before calling

// quick structural pre-check: zlib header + plausible size
if (!(((payload[0] << 8) + payload[1]) % 31 === 0 && (payload[0] & 0x0f) === 8)) {
  throw new Error("Not a zlib stream");
}

Type guard

function hasValidZlibHeader(d: Uint8Array): boolean {
  return d.byteLength >= 2 && (d[0] & 0x0f) === 8 && d[0] >> 4 <= 7 && ((d[0] << 8) + d[1]) % 31 === 0;
}

Try / catch

try {
  const out = inflateZlib(payload, expectedLength);
} catch (e) {
  if (e instanceof Error && e.message === "deflate: invalid distance symbol") {
    throw new Error("Invalid distance code in FBX compressed array — data corrupt", { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: inflateCompressedBlock decodes a length symbol, then distanceTree.decode(reader) returns 30 or 31 (fixed distance tree encodes 32 symbols of 5 bits each; the top two are illegal per RFC 1951).

Common situations: Decoding non-deflate bytes that happen to pass the zlib header check; corrupt FBX payload mid-block; wrong buffer slice causing bit misalignment so subsequent codes are garbage.

Related errors


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