egametang/ET · error · Exception
invalid level: {level} (expected: {LEVEL_1} or {LEVEL_2})
Error message
invalid level: {level} (expected: {LEVEL_1} or {LEVEL_2}) What it means
FastLZ.Decompress reads a 3-bit compression level from the first byte of the input (bits 5-7, plus 1). The only valid levels are LEVEL_1 and LEVEL_2. If the derived level is neither, the input is not a valid FastLZ-compressed block — it is corrupted, truncated, or produced by a different algorithm/version.
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Core/Compression/FastLZ.cs:517
return op;
}
/**
* Decompress a block of compressed data and returns the size of the decompressed block.
* If error occurs, e.g. the compressed data is corrupted or the output buffer is not large
* enough, then 0 (zero) will be returned instead.
*
* Decompression is memory safe and guaranteed not to write the output buffer
* more than what is specified in outLength.
*/
public static int Decompress(byte[] input, int inOffset, int inLength,
byte[] output, int outOffset, int outLength)
{
//int level = ((*(const flzuint8*)input) >> 5) + 1;
int level = (input[inOffset] >> 5) + 1;
if (level != LEVEL_1 && level != LEVEL_2)
{
throw new Exception($"invalid level: {level} (expected: {LEVEL_1} or {LEVEL_2})");
}
// const flzuint8* ip = (const flzuint8*) input;
int ip = 0;
// flzuint8* op = (flzuint8*) output;
int op = 0;
// flzuint32 ctrl = (*ip++) & 31;
long ctrl = input[inOffset + ip++] & 31;
int loop = 1;
do
{
// const flzuint8* refs = op;
int refs = op;
// flzuint32 len = ctrl >> 5;
long len = ctrl >> 5;
// flzuint32 ofs = (ctrl & 31) << 8;
long ofs = (ctrl & 31) << 8;View on GitHub (pinned to 5cab01f7a8)
Solutions
- Verify the data source: confirm it was produced by FastLZ.Compress and not another compressor.
- Check inOffset points to the true start of the FastLZ block (not mid-buffer).
- If data is from a cache file, clear/regenerate the cache to rule out corruption.
- Add a length/header sanity check on input before calling Decompress.
Example fix
// before
FastLZ.Decompress(data, 0, data.Length, outBuf, 0, outBuf.Length);
// after — validate first byte before decompressing
int lvl = (data[0] >> 5) + 1;
if (lvl != FastLZ.LEVEL_1 && lvl != FastLZ.LEVEL_2)
{
throw new InvalidOperationException("input is not FastLZ data");
}
FastLZ.Decompress(data, 0, data.Length, outBuf, 0, outBuf.Length); Defensive patterns
Strategy: validation
Validate before calling
int lvl = (input[inOffset] >> 5) + 1;
if (lvl != FastLZ.LEVEL_1 && lvl != FastLZ.LEVEL_2) throw new InvalidOperationException("not FastLZ data"); Try / catch
try { FastLZ.Decompress(input, inOffset, inLength, output, outOffset, outLength); }
catch (Exception ex) { Log.Error($"FastLZ decompress failed, data may be corrupt: {ex}"); /* regenerate cache */ } Prevention
- Validate the header byte before decompressing.
- Confirm input was produced by FastLZ.Compress.
- Clear and regenerate compressed caches after version upgrades.
When it happens
Trigger: Passing a byte array that was not compressed by FastLZ; passing data compressed by FastLZ level 2 to a reader expecting level 1 (only if the header byte is invalid); a truncated or bit-flipped compressed stream whose first byte is wrong; using the wrong offset so the header byte read is not the FastLZ header.
Common situations: Corrupted cached navmesh/voxel data on disk; a version change in the compression format; reading past the wrong offset; data produced by a different LZ codec (LZ4, zlib) being fed to FastLZ.Decompress.
Related errors
- Invalid magic
- Serialization_MismatchedCount
- Unsupported compression type {compressionType}
- vector2f index out of range
- Empty path
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/43d4e7a3a48e49bd.
Report an issue: GitHub.