Anuken/Mindustry · error · IOException

Error reading region "{}": read length mismatch. Expected: {

Error message

Error reading region "{}": read length mismatch. Expected: {}; Actual: {}

What it means

Thrown by SaveFileReader.readRegion after a chunk is read successfully but the declared chunk length does not match the number of bytes actually consumed from the counter (counter.count - 4, excluding the 4-byte length prefix). A length mismatch means the reader consumed a different number of bytes than the writer declared, indicating structural corruption or a serialization/version mismatch.

Source

Thrown at core/src/mindustry/io/SaveFileReader.java:97

    protected static final Reads chunkReads = new Reads(null);
    protected static boolean chunkNested = false;

    public static String mapFallback(String name){
        return fallback.get(name, name);
    }

    //TODO: unify readRegion with readChunk, they do the same thing and both should have good error messages
    public void readRegion(String name, DataInput stream, CounterInputStream counter, IORunner<DataInput> cons) throws IOException{
        counter.resetCount();
        int length;
        try{
            length = readChunk(stream, (chunkStream, len) -> cons.accept(chunkStream));
        }catch(Throwable e){
            throw new IOException("Error reading region \"" + name + "\".", e);
        }

        if(length != counter.count - 4){
            throw new IOException("Error reading region \"" + name + "\": read length mismatch. Expected: " + length + "; Actual: " + (counter.count - 4));
        }
    }

    public void writeRegion(String name, DataOutput stream, IORunner<DataOutput> cons) throws IOException{
        try{
            writeChunk(stream, writes -> cons.accept(writes.output));
        }catch(Throwable e){
            throw new IOException("Error writing region \"" + name + "\".", e);
        }
    }

    /** Write a chunk of input to the stream. An integer of some length is written first, followed by the data. */
    public void writeChunk(DataOutput output, IORunner<Writes> runner) throws IOException{
        boolean wasNested = chunkNested;

        chunkNested = true;

        //regions can be nested once, so use a different output if it's already nested

View on GitHub (pinned to f695ad7e60)

Solutions

  1. Load the save in the exact game version that wrote it (region layouts are version-specific).
  2. If you changed serialization code, ensure read/write byte counts match exactly across versions (use revisions for compatible changes).
  3. Restore from a backup if the file is corrupt.
  4. Catch the IOException and surface expected vs actual counts to aid diagnosis.

Example fix

// before: mismatched read size across versions
// (reading a short where an int was written shifts the counter)

// after: keep read/write sizes in sync
// write: stream.writeInt(value);
// read:  value = stream.readInt(); // must match the write size
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate version compatibility before reading regions
if(SaveIO.getSaveWriter(version) == null || !isCompatible(version)){
    throw new IOException("Incompatible save version " + version);
}

Try / catch

try{ ver.readRegion(name, stream, counter, cons); }catch(IOException e){ Log.err("Length mismatch in '" + name + "'", e); throw e; }

Prevention

When it happens

Trigger: readChunk returns a length L, but counter.count - 4 != L. Happens when a field is read with wrong size across versions (e.g. byte vs short vs int), a region's format changed, or the stream is misaligned by corruption.

Common situations: Loading a save written by a different version whose region layout shifted; a mod altered serialization in an incompatible way; bit-level corruption shifting alignment; hand-edited save files.

Related errors


AI-assisted analysis of Anuken/Mindustry@f695ad7e60 (2026-08-14). Data as JSON: /api/errors/0463aac94db22539. Report an issue: GitHub.