BabylonJS/Babylon.js · error
deflate: expected byte alignment
Error message
deflate: expected byte alignment
What it means
ensureByteAligned fires when a byte-oriented read (readByte or readUint16LE, used only for stored deflate blocks) is attempted while the bit reader still holds unconsumed bits in its buffer. Stored blocks in DEFLATE must start on a byte boundary; hitting this means the bit-level alignment logic and the byte-level reads got out of sync, i.e. the stream is malformed or was mis-decoded up to this point.
Source
Thrown at packages/dev/loaders/src/FBX/parsers/zlibInflate.ts:128
if (this.byteOffset + 2 > this.endOffset) {
throw new Error("zlib: unexpected end of input");
}
const value = this.input[this.byteOffset] | (this.input[this.byteOffset + 1] << 8);
this.byteOffset += 2;
return value;
}
public readByte(): number {
this.ensureByteAligned();
if (this.byteOffset >= this.endOffset) {
throw new Error("zlib: unexpected end of input");
}
return this.input[this.byteOffset++];
}
private ensureByteAligned(): void {
if (this.bitCount !== 0) {
throw new Error("deflate: expected byte alignment");
}
}
private ensureBits(count: number): void {
while (this.bitCount < count) {
if (this.byteOffset >= this.endOffset) {
throw new Error("zlib: unexpected end of input");
}
this.bitBuffer |= this.input[this.byteOffset++] << this.bitCount;
this.bitCount += 8;
}
}
}
class OutputWriter {
private offset = 0;
private adlerA = 1;
private adlerB = 0;
View on GitHub (pinned to 0592b347b8)
Solutions
- Confirm the payload really is a zlib stream (header check passes and it came from a standard deflate compressor).
- Check any custom modifications to the inflate loop — every stored block must call alignToByte() before readUint16LE/readByte.
- Ensure the BitReader is used by a single synchronous inflate call, not shared across concurrent decodes.
- If the file is suspect, try decompressing it with an independent zlib implementation (e.g. pako) to confirm where the corruption starts.
Example fix
// before reader.readBits(3); // leftover bits consumed ad hoc const len = reader.readUint16LE(); // after reader.alignToByte(); const len = reader.readUint16LE();
Defensive patterns
Strategy: try-catch
Validate before calling
function isZlibStream(buf: Uint8Array): boolean {
return buf.byteLength >= 6 && (buf[0] & 0x0f) === 8 && ((buf[0] << 8) + buf[1]) % 31 === 0;
} Try / catch
try {
return inflateZlib(payload, count);
} catch (e) {
if (e instanceof Error && e.message === "deflate: expected byte alignment") {
throw new Error("payload is not a valid deflate stream (alignment error) — wrong offset or corrupt file");
}
throw e;
} Prevention
- Never share a BitReader across concurrent decodes; inflate synchronously per payload.
- If you modify the inflate loop, always call alignToByte() before stored-block byte reads.
- Confirm payloads come from a standard zlib compressor, not arbitrary bytes.
- Use pako to bisect where a suspicious stream first diverges.
When it happens
Trigger: readUint16LE or readByte is called when bitCount !== 0. In practice this happens only if inflateStoredBlock's alignToByte() contract is violated — i.e. corrupt preceding data caused the decoder to misinterpret block boundaries, or the internal reader state was corrupted by concurrent/shared use.
Common situations: Parsing a corrupted or non-deflate buffer that happened to pass the zlib header check; a modified/patched inflate pipeline that reads bits without aligning before stored blocks; sharing a BitReader across async tasks so state is interleaved.
Related errors
- deflate: invalid block type
- deflate: distance out of range
- deflate: invalid huffman code lengths
- deflate: invalid huffman code
- deflate: invalid stored block length
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/f3e98c5ebcc3a507.
Report an issue: GitHub.