Anuken/Mindustry · error · RuntimeException

Invalid array size: {}

Error message

Invalid array size: {}

What it means

TypeIO.readObject case 6 (IntSeq) reads a short length and rejects it if it exceeds maxArraySize (1000, or 200 in unsafe contexts). This is a server-side sanity check against malicious or corrupt packets claiming an oversized IntSeq. Plain RuntimeException, not ArcRuntimeException.

Source

Thrown at core/src/mindustry/io/TypeIO.java:203

        return switch(type){
            case 0 -> null;
            case 1 -> read.i();
            case 2 -> read.l();
            case 3 -> read.f();
            case 4 -> {
                byte exists = read.b();
                if(exists != 0){
                    //in a safe context, strings can only be 1200 chars
                    yield read.str(safe ? 1200 : 0);
                }else{
                    yield null;
                }
            }
            case 5 -> mapper == null ? content.getByID(ContentType.all[read.b()], read.s()) : mapper.get(ContentType.all[read.b()], read.s());
            case 6 -> {
                if(!allowArrays) throw new RuntimeException("Nested arrays are not allowed");
                short len = read.s();
                if(len > maxArraySize) throw new RuntimeException("Invalid array size: " + len);
                IntSeq arr = new IntSeq(len);
                for(int i = 0; i < len; i ++) arr.add(read.i());
                yield arr;
            }
            case 7 -> new Point2(read.i(), read.i());
            case 8 -> {
                if(!allowArrays) throw new RuntimeException("Nested arrays are not allowed");
                int len = read.ub();
                Point2[] out = new Point2[len];
                for(int i = 0; i < len; i ++) out[i] = Point2.unpack(read.i());
                yield out;
            }
            case 9 -> content.<UnlockableContent>getByID(ContentType.all[read.b()], read.s()).techNode;
            case 10 -> read.bool();
            case 11 -> read.d();
            case 12 -> !box ? world.build(read.i()) : new BuildingBox(read.i());
            case 13 -> LAccess.all[read.s()];
            case 14 -> {

View on GitHub (pinned to f695ad7e60)

Solutions

  1. Ensure the client respects the same maxArraySize caps when writing (writeObject already enforces 1000).
  2. Treat this as a protocol violation: disconnect/log the offending client rather than retrying.
  3. If developing a mod, never hand-craft TypeIO bytes; use writeObject/readObject pairs.

Example fix

// before (client)
write.s((short)5000); // bypasses writeObject; server read throws

// after
TypeIO.writeObject(write, intSeq); // writeObject enforces the 1000 cap
// server: catch RuntimeException and kick the offending connection
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
    Object o = TypeIO.readObject(read);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Invalid array size")) {
        // protocol violation; disconnect offending client
    }
}

Prevention

When it happens

Trigger: A client packet or save region where the IntSeq length short is greater than the effective maxArraySize; in safe contexts the limit is 1000, in non-safe (build-plan) contexts it is 200.

Common situations: A malicious/corrupt client sending an inflated length to force a large allocation; a version drift that misreads bytes as a length.

Related errors


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