Anuken/Mindustry · error · IOException
Incorrect header! Expecting: {}; Actual: {}
Error message
Incorrect header! Expecting: {}; Actual: {} What it means
SaveIO.readHeader reads exactly header.length (4) bytes and compares them to {'M','S','A','V'}. Any mismatch throws IOException. This is the first validation performed on every save stream (before version read), so a wrong header means the file is not a Mindustry save at all or its beginning is corrupt.
Source
Thrown at core/src/mindustry/io/SaveIO.java:190
ver.read(stream, counter, new SaveReadState(context));
Events.fire(new SaveLoadEvent(context.isMap()));
}catch(Throwable e){
throw new SaveException(e);
}finally{
world.setGenerating(false);
content.setTemporaryMapper(null);
}
}
public static SaveVersion getVersion(){
return versionArray.peek();
}
public static void readHeader(DataInput input) throws IOException{
byte[] bytes = new byte[header.length];
input.readFully(bytes);
if(!Arrays.equals(bytes, header)){
throw new IOException("Incorrect header! Expecting: " + Arrays.toString(header) + "; Actual: " + Arrays.toString(bytes));
}
}
public static class SaveException extends RuntimeException{
public SaveException(Throwable throwable){
super(throwable);
}
}
}
View on GitHub (pinned to f695ad7e60)
Solutions
- Confirm the file is a real .msav produced by SaveIO.write (it always writes the MSAV header first).
- Inspect the Actual bytes in the message: random bytes indicate corruption; ASCII text indicates a wrong file.
- Use SaveIO.isSaveValid to gate the UI; it catches this IOException and returns false.
- Restore from the -backup file generated by SaveIO.save before each write.
Example fix
// before
try (var stream = SaveIO.getStream(file)) {
SaveIO.readHeader(stream);
}
// after
if (!SaveIO.isSaveValid(file)) {
throw new IllegalArgumentException(file + " is not a valid Mindustry save (bad or missing MSAV header)");
} Defensive patterns
Strategy: validation
Validate before calling
if (!SaveIO.isSaveValid(file)) {
throw new IllegalArgumentException("Not a valid Mindustry save (bad MSAV header): " + file);
} Type guard
null
Try / catch
try {
SaveIO.readHeader(stream);
} catch (IOException e) {
// header mismatch; file is not a save
} Prevention
- Filter file choosers to the .msav extension.
- Use isSaveValid before any readHeader/getMeta call.
- Restore from the -backup file when the primary header is corrupt.
When it happens
Trigger: readHeader is called by both getMeta and load before anything else; feeding a non-.msav file, a text file, or a truncated/overwritten file whose first 4 bytes are not the MSAV magic. The reported Actual array shows what bytes were read.
Common situations: User selected the wrong file (e.g. a .png or .zip); the save was partially overwritten by another process; an OS copy truncated the file; feeding a raw deflated stream without the header.
Related errors
- Could not skip bytes. Expected length: {}; Actual length: {}
- Failed to read tile entity of block: {}
- Unknown save version: {}. Are you trying to load a save from
- Invalid asset type ID: {}. You are likely loading trying to
AI-assisted analysis of Anuken/Mindustry@f695ad7e60 (2026-08-14).
Data as JSON: /api/errors/441c4f42cb67560f.
Report an issue: GitHub.