Anuken/Mindustry · error · IllegalArgumentException
Invalid class ID for `@` detected (found: @). Potential fixe
Error message
Invalid class ID for `@` detected (found: @). Potential fixes:
- Register with `EntityMapping.register("some-unique-name", @::new)` to get an ID, and store it somewhere.
- Override `@#classId()` to return that ID. What it means
After a constructor is set, checkEntityMapping verifies the entity's classId maps to a valid constructor in EntityMapping AND that the class's own classId() points back to a constructor whose entity's classId() matches (i.e. the class registered its own ID). This catches the common pitfall of subclassing a unit entity without registering an ID.
Source
Thrown at core/src/mindustry/type/UnitType.java:881
"hover": ElevationMoveUnit::create
"tether": BuildingTetherPayloadUnit::create
"crawl": CrawlUnit::create
""", name));
// Often modders improperly only sets `constructor = ...` without mapping. Try to mitigate that.
// In most cases, if the constructor is a Vanilla class, things should work just fine.
if(EntityMapping.map(name) == null) EntityMapping.nameMap.put(name, constructor);
// Sanity checks; this is an EXTREMELY COMMON pitfalls Java modders fall into.
int classId = example.classId();
if(
// Check if `classId()` even points to a valid constructor...
EntityMapping.map(classId) == null ||
// ...or if the class doesn't register itself and uses the ID of its base class.
classId != ((Entityc)EntityMapping.map(classId).get()).classId()
){
String type = example.getClass().getSimpleName();
throw new IllegalArgumentException(Strings.format("""
Invalid class ID for `@` detected (found: @). Potential fixes:
- Register with `EntityMapping.register("some-unique-name", @::new)` to get an ID, and store it somewhere.
- Override `@#classId()` to return that ID.
""", type, classId, type, type));
}
}
void initPathType(){
if(flowfieldPathType == -1){
flowfieldPathType =
naval ? Pathfinder.costNaval :
allowLegStep ? Pathfinder.costLegs :
flying ? Pathfinder.costNone :
hovering ? Pathfinder.costHover :
Pathfinder.costGround;
}
if(pathCost == null){View on GitHub (pinned to f695ad7e60)
Solutions
- Register a unique id: int id = EntityMapping.register("my-mod-myunit", MyUnit::new); store it.
- Override classId() in your entity subclass to return that stored id.
- Ensure the registered constructor's product reports the same classId (consistency check).
Example fix
// before
public class MyUnit extends UnitEntity { } // invalid class ID
// after
public class MyUnit extends UnitEntity {
public static int classId;
@Override public int classId(){ return classId; }
}
// during mod init:
MyUnit.classId = EntityMapping.register("my-mod-myunit", MyUnit::new); Defensive patterns
Strategy: validation
Validate before calling
// Verify entity ID registration consistency before use.
int id = example.classId();
Func<Entityc> factory = EntityMapping.map(id);
if(factory == null || ((Entityc)factory.get()).classId() != id) {
throw new IllegalArgumentException("Entity class ID not registered: " + example.getClass().getName());
} Type guard
boolean classIdConsistent(Entityc example){
int id = example.classId();
Func<Entityc> f = EntityMapping.map(id);
return f != null && ((Entityc)f.get()).classId() == id;
} Try / catch
try {
type.checkEntityMapping(example);
} catch(IllegalArgumentException e) {
if(e.getMessage().startsWith("Invalid class ID")) { /* register + override classId */ }
else throw e;
} Prevention
- Register custom entity classes with EntityMapping.register at mod init.
- Override classId() to return the registered id.
- Keep the registered constructor and classId() mutually consistent.
When it happens
Trigger: A custom unit entity subclass either has no EntityMapping entry for its classId, or its classId collides with the base class because it never registered/overrode the ID.
Common situations: Modder subclasses UnitEntity/MechUnit etc. without calling EntityMapping.register and overriding classId(); entity deserialization would then create the wrong type.
Related errors
- No constructor set up for unit '@': Assign `constructor = [y
- No constructor set up for unit '{name}', add this argument t
- Two content objects defined with the same name: '{content.na
- Resolving arbitrary classes (${className}) is not allowed. U
- Expecting an object, but found: '${jsonMap}'
AI-assisted analysis of Anuken/Mindustry@f695ad7e60 (2026-08-14).
Data as JSON: /api/errors/057c902c5cc2dbfa.
Report an issue: GitHub.