Anuken/Mindustry · error · IOException
Failed to read tile entity of block: {}
Error message
Failed to read tile entity of block: {} What it means
In SaveVersion.readMap, when a center tile block has a building, the per-tile entity region is read via readChunkReads then tile.build.readAll(in, revision). Any Throwable thrown during that read is caught and rethrown as an IOException with the block name attached, which then surfaces through readRegion as an 'Error reading region map' wrapper. The original cause is preserved as the exception cause.
Source
Thrown at core/src/mindustry/io/SaveVersion.java:369
//must be assigned after setBlock, because that can reset data
if(hadData){
tile.data = data;
tile.floorData = floorData;
tile.overlayData = overlayData;
tile.extraData = extraData;
context.onReadTileData();
}
if(hadEntity){
if(isCenter){ //only read entity for center blocks
if(block.hasBuilding()){
try{
readChunkReads(stream, (in, len) -> {
byte revision = in.b();
tile.build.readAll(in, revision);
});
}catch(Throwable e){
throw new IOException("Failed to read tile entity of block: " + block, e);
}
}else{
//skip the entity region, as the entity and its IO code are now gone
skipChunk(stream);
}
context.onReadBuilding();
}
}else if(!hadData){ //never read consecutive blocks if there's data
int consecutives = stream.readUnsignedByte();
for(int j = i + 1; j < i + 1 + consecutives; j++){
context.tile(j).setBlock(block);
}
i += consecutives;
}
}View on GitHub (pinned to f695ad7e60)
Solutions
- Inspect the wrapped cause (getCause) and the block name in the message: a NoSuchField/ClassCastException indicates a version drift, an EOFException indicates truncation.
- Re-save the world in a build whose block IO matches, then load.
- Ensure the same mods (and versions) that created the save are enabled when loading.
- If you author a custom block, implement readAll defensively across revisions and bump the revision byte only when adding fields.
- Use the -backup file via SaveIO.load(Fi) which already retries once.
Example fix
// before
SaveIO.load(file); // IOException("Failed to read tile entity of block: <name>")
// after
try {
SaveIO.load(file);
} catch (SaveException e) {
Throwable c = e.getCause(); // may chain through "Error reading region map"
while (c != null && c.getCause() != null) c = c.getCause();
Log.err("Tile entity read failed for save @", file, c);
} Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try {
SaveIO.load(file);
} catch (SaveException e) {
Throwable c = e.getCause();
while (c != null && c.getCause() != null) c = c.getCause();
if (c != null && c.getMessage() != null && c.getMessage().startsWith("Failed to read tile entity")) {
// block IO mismatch; report block name
}
} Prevention
- Keep the same game build (and mods) when loading a save that created it.
- Implement readAll defensively across revisions for custom blocks.
- Use the backup file when the primary entities region is corrupt.
When it happens
Trigger: Block class schema changed between save and load (added/removed serialized fields); modded block whose class is missing; corrupt entity byte stream causing ArrayIndexOutOfBounds / negative array size in readAll; revision byte does not match a known read revision of the block.
Common situations: Loading a save after updating the game and a block's serialization changed without a migration path; loading a modded save without the mod enabled; partial save corruption in the entities region; a custom block whose readAll implementation throws.
Related errors
- Could not skip bytes. Expected length: {}; Actual length: {}
- Unknown save version: {}. Are you trying to load a save from
- Incorrect header! Expecting: {}; Actual: {}
- Invalid asset type ID: {}. You are likely loading trying to
- Nested arrays are not allowed
AI-assisted analysis of Anuken/Mindustry@f695ad7e60 (2026-08-14).
Data as JSON: /api/errors/63ac76d14951abf6.
Report an issue: GitHub.