{"record":{"id":"96921fd70ae062ac","repo":"Anuken/Mindustry","slug":"failed-to-read-tile-entity-of-block-96921f","errorCode":null,"errorMessage":"Failed to read tile entity of block: ","messagePattern":"Failed to read tile entity of block: ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"core/src/mindustry/io/versions/ShortChunkSaveVersion.java","lineNumber":127,"sourceCode":"                //must be assigned after setBlock, because that can reset data\n                if(hadDataNew){\n                    tile.data = data;\n                    tile.floorData = floorData;\n                    tile.overlayData = overlayData;\n                    tile.extraData = extraData;\n                    context.onReadTileData();\n                }\n\n                if(hadEntity){\n                    if(isCenter){ //only read entity for center blocks\n                        if(block.hasBuilding()){\n                            try{\n                                readLegacyShortChunk(stream, (in, len) -> {\n                                    byte revision = in.b();\n                                    tile.build.readAll(in, revision);\n                                });\n                            }catch(Throwable e){\n                                throw new IOException(\"Failed to read tile entity of block: \" + block, e);\n                            }\n                        }else{\n                            //skip the entity region, as the entity and its IO code are now gone\n                            skipLegacyShortChunk(stream);\n                        }\n\n                        context.onReadBuilding();\n                    }\n                }else if(hadDataOld || hadDataNew){ //never read consecutive blocks if there's any kind of data\n                    if(hadDataOld){\n                        tile.setBlock(block);\n                        //the old data format was only read in the case where there is no building, and only contained a single byte\n                        tile.data = stream.readByte();\n                    }\n                }else{\n                    int consecutives = stream.readUnsignedByte();\n\n                    for(int j = i + 1; j < i + 1 + consecutives; j++){","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/core/src/mindustry/io/versions/ShortChunkSaveVersion.java#L109-L145","documentation":"ShortChunkSaveVersion (the older 'short chunk' save format) reads building data via readLegacyShortChunk then tile.build.readAll(in, revision). Any Throwable from that read is wrapped in an IOException naming the block. Same pattern as LegacySaveVersion but for the short-chunk format.","triggerScenarios":"Loading a short-chunk legacy save whose building data for a block is corrupt or unreadable by the current build.readAll.","commonSituations":"Old short-chunk saves; block class changes since the save; partial corruption.","solutions":["Inspect the wrapped cause (e.getCause()) for the real failure.","If the save is too old, start fresh.","Align mods to the versions that wrote the save."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    shortChunkVersion.read(stream, context);\n} catch(IOException e) {\n    Log.err(\"Save load failed for block: \" + e.getMessage(), e.getCause());\n    // e.getMessage() names the block; e.getCause() is the real failure\n}","preventionTips":["Keep mods aligned with the saves you load.","For short-chunk-era saves, prefer starting fresh if load fails.","Log the wrapped cause (getCause) to find the real read failure."],"tags":["save","legacy","deserialization","migration"],"backgroundTag":null,"analyzedSha":"f695ad7e60323ebced984fa26d0bcf0bc54296b4","analyzedAt":"2026-08-14T04:31:16.262Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}