{"record":{"id":"3ceee08bb7b66db4","repo":"Anuken/Mindustry","slug":"unknown-revision-rev-for-entity-type-name","errorCode":null,"errorMessage":"Unknown revision '{REV}' for entity type '{name}'","messagePattern":"Unknown revision '(.+?)' for entity type '(.+?)'","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"annotations/src/main/java/mindustry/annotations/entity/EntityIO.java","lineNumber":121,"sourceCode":"                //check for the right revision\n                Revision rev = revisions.get(i);\n                if(i == 0){\n                    cont(\"if(REV == $L)\", rev.version);\n                }else{\n                    ncont(\"else if(REV == $L)\", rev.version);\n                }\n\n                //add code for reading revision\n                for(RevisionField field : rev.fields){\n                    if(fieldHasAnno(field, allFields, NoSerialize.class)) continue;\n                    //if the field doesn't exist, the result will be an empty string, it won't get assigned\n                    io(field.type, presentFields.contains(field.name) ? \"this.\" + field.name + \" = \" : \"\", false);\n                }\n            }\n\n            //throw exception on illegal revisions\n            ncont(\"else\");\n            st(\"throw new IllegalArgumentException(\\\"Unknown revision '\\\" + REV + \\\"' for entity type '\" + name + \"'\\\")\");\n            econt();\n        }\n    }\n\n    boolean fieldHasAnno(RevisionField field, Seq<Svar> allFields, Class<? extends Annotation> type){\n        Svar var = allFields.find(s -> s.name().equals(field.name));\n        return var != null && var.has(type);\n    }\n\n    void writeSync(MethodSpec.Builder method, boolean write, Seq<Svar> allFields) throws Exception{\n        this.method = method;\n        this.write = write;\n\n        if(write){\n            //write uses most recent revision\n            for(RevisionField field : revisions.peek().fields){\n                if(fieldHasAnno(field, allFields, NoSync.class)) continue;\n","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/Anuken/Mindustry/blob/f695ad7e60323ebced984fa26d0bcf0bc54296b4/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java#L103-L139","documentation":"Generated by the Mindustry annotation processor (EntityIO) into entity read() methods. Entity serialization tracks revisions: each known revision maps to a set of field reads. The generated code handles revisions in if/else branches; the final 'else' throws IllegalArgumentException with the unknown REV. This means the saved entity data carries a revision number the generated reader was not built to understand.","triggerScenarios":"Deserializing an entity whose saved revision is greater than the highest revision the compiled entity code knows. The literal in the message ('for entity type <name>') is baked in at annotation-processing time, while REV is the runtime value read from the stream.","commonSituations":"Loading a save created by a newer game build (which bumped the entity revision) on an older build; partial rebuild where entity revision metadata drifted; mixing entity classes compiled against different annotation-processor versions.","solutions":["Update to the game build that wrote the save (newer builds know higher revisions).","If you maintain entity revisions, verify your @EntityDef / RevisionField declarations match the writer side.","Do not downgrade saves across versions that changed entity field revisions; migrate forward instead.","Regenerate entity sources (rebuild) so the annotation processor emits the current revision branches."],"exampleFix":"// before: older build reading newer save -> generated else branch throws\n// after: rebuild against current annotations, or load in the build that authored the save\n// (no runtime patch; revision branches are compile-time generated)","handlingStrategy":"try-catch","validationCode":"// not possible at runtime: revisions are baked into generated code\n// guard by checking save version compatibility before deserializing entities\nif(saveVersion > currentMaxVersion){\n    throw new IOException(\"Save from a newer version; cannot read entity revisions\");\n}","typeGuard":null,"tryCatchPattern":"try{ entity.read(reads); }catch(IllegalArgumentException e){ Log.err(\"Entity revision unknown\", e); /* discard entity */ }","preventionTips":["Keep entity revision metadata consistent across write/read builds.","Rebuild generated entity sources after changing @EntityDef fields.","Never load newer-version saves on older builds.","Version-gate saves before attempting entity deserialization."],"tags":["entity","serialization","save-compat","codegen","annotations"],"backgroundTag":null,"analyzedSha":"f695ad7e60323ebced984fa26d0bcf0bc54296b4","analyzedAt":"2026-08-14T04:31:16.262Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}