Anuken/Mindustry · error · IOException

Error reading region "{}".

Error message

Error reading region "{}".

What it means

Thrown by SaveFileReader.readRegion when any Throwable escapes readChunk while reading a named save region. readRegion wraps the chunk read in try/catch and rethrows an IOException tagged with the region name, chaining the original cause. This is the generic 'something went wrong reading this region' wrapper used across save/map loading.

Source

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

    protected static final ReusableByteOutStream byteOutput = new ReusableByteOutStream(), byteOutput2 = new ReusableByteOutStream();
    protected static final DataOutputStream dataBytes = new DataOutputStream(byteOutput), dataBytes2 = new DataOutputStream(byteOutput2);
    protected static final Writes writes1 = new Writes(dataBytes), writes2 = new Writes(dataBytes2);
    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;

View on GitHub (pinned to f695ad7e60)

Solutions

  1. Inspect the chained cause (IOException.getCause()) for the real failure (EOF, ClassNotFound, etc.).
  2. If the file is corrupt/truncated, restore from a backup or re-download.
  3. If a version mismatch, load in the matching game version.
  4. Catch IOException at the load boundary and report the region + cause to the user.

Example fix

// before
ver.readRegion("meta", stream, counter, cons);

// after
try{
    ver.readRegion("meta", stream, counter, cons);
}catch(IOException e){
    Log.err("Failed reading region 'meta'", e.getCause());
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// cannot fully pre-validate a region without reading it; pre-check version instead
if(SaveIO.getSaveWriter(version) == null){ throw new IOException("Unsupported save version"); }

Try / catch

try{ ver.readRegion(name, stream, counter, cons); }catch(IOException e){ Log.err("Region '" + name + "' unreadable", e.getCause()); throw e; }

Prevention

When it happens

Trigger: Any exception (IOException, EOFException, RuntimeException) during deserialization of a save region (e.g. 'meta', 'map', 'entities') bubbles up wrapped as 'Error reading region "<name>".'. Caused by truncation, corruption, or a deserialization bug.

Common situations: Corrupt or partially-written save file; truncated download of a map; version-skew where a region's contents differ from what the reader expects; disk read error mid-stream.

Related errors


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