Anuken/Mindustry · error · IOException

Not a schematic file (missing header).

Error message

Not a schematic file (missing header).

What it means

Thrown by Schematics.read(InputStream) when the first 4 bytes of the stream do not equal the schematic header bytes {'m','s','c','h'}. The header is a magic-number guard so non-schematic files are rejected before any structured parsing. Any byte mismatch (including EOF returning -1) triggers the throw.

Source

Thrown at core/src/mindustry/game/Schematics.java:573

            return read(new ByteArrayInputStream(Base64Coder.decode(schematic.trim())));
        }catch(IOException e){
            throw new RuntimeException(e);
        }
    }

    public static Schematic read(Fi file) throws IOException{
        Schematic s = read(new DataInputStream(file.read(1024)));
        if(!s.tags.containsKey("name")){
            s.tags.put("name", file.nameWithoutExtension());
        }
        s.file = file;
        return s;
    }

    public static Schematic read(InputStream input) throws IOException{
        for(byte b : header){
            if(input.read() != b){
                throw new IOException("Not a schematic file (missing header).");
            }
        }

        int ver = input.read();

        if(ver > version) throw new IOException("Unknown version: " + ver + " (are you trying to load a schematic from a newer version of the game?)");

        try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){
            short width = stream.readShort(), height = stream.readShort();

            if(limitSchematicSize && (width > 128 || height > 128)) throw new IOException("Invalid schematic: Too large (max possible size is 128x128)");

            StringMap map = new StringMap();
            int tags = stream.readUnsignedByte();
            for(int i = 0; i < tags; i++){
                map.put(stream.readUTF(), stream.readUTF());
            }

View on GitHub (pinned to f695ad7e60)

Solutions

  1. Verify the file is a real schematic (first bytes should be 'm','s','c','h').
  2. Check file extension and source; re-export the schematic from a known-good source.
  3. If reading from a network/resource, ensure it isn't truncated (content-length vs actual bytes).
  4. Catch IOException around Schematics.read and report a friendly 'invalid schematic' message to the user.

Example fix

// before
Schematic s = Schematics.read(file); // may throw on non-schematic

// after
try{
    Schematic s = Schematics.read(file);
}catch(IOException e){
    ui.showErrorMessage("Not a valid schematic file.");
    Log.err(e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// quick header sniff before full parse
try(InputStream in = file.read(4)){
    byte[] magic = {'m','s','c','h'};
    for(byte b : magic){ if(in.read() != b){ throw new IOException("Not a schematic"); } }
}

Try / catch

try{ Schematic s = Schematics.read(file); }catch(IOException e){ ui.showErrorMessage("Invalid schematic file"); Log.err(e); }

Prevention

When it happens

Trigger: Passing a file/stream to Schematics.read that is not a schematic: wrong file type, a renamed .png/.zip/.msav, a truncated/empty file, or a corrupt schematic. input.read() returning -1 (end of stream) compares != to the header byte and throws.

Common situations: User imports the wrong file as a schematic; a schematic file was corrupted by a transfer/sync; reading a schematic tag stored under a different format; pointing read() at a save (.msav) instead of a schematic.

Related errors


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