t8y2/dbx · error · IOException
H2 MVStore file is too small to contain valid headers: " + f
Error message
H2 MVStore file is too small to contain valid headers: " + file
What it means
readMvStoreFormat reads the first two 4KB blocks of a .mv.db file because MVStore stores a header in each of the first two blocks. If fewer than BLOCK_SIZE*2 bytes can be read the file cannot hold valid headers, so an IOException is thrown instead of parsing garbage.
Source
Thrown at agents/drivers/h2/src/main/java/com/dbx/agent/h2/H2FileFormatDetector.java:46
if (pageStoreExists && mvStoreExists) {
throw new IOException("Both H2 PageStore and MVStore files exist for " + base + "; choose an explicit H2 driver profile");
}
if (pageStoreExists) {
return OptionalInt.of(1);
}
if (!mvStoreExists) {
return OptionalInt.empty();
}
return OptionalInt.of(readMvStoreFormat(mvStore));
}
private static int readMvStoreFormat(Path file) throws IOException {
byte[] bytes;
try (InputStream input = Files.newInputStream(file)) {
bytes = input.readNBytes(BLOCK_SIZE * 2);
}
if (bytes.length < BLOCK_SIZE * 2) {
throw new IOException("H2 MVStore file is too small to contain valid headers: " + file);
}
List<StoreHeader> headers = new ArrayList<>();
for (int block = 0; block < 2; block++) {
StoreHeader header = parseHeader(bytes, block * BLOCK_SIZE);
if (header != null) {
headers.add(header);
}
}
return headers.stream()
.max(Comparator.comparingLong(StoreHeader::version))
.orElseThrow(() -> new IOException("Cannot determine the H2 MVStore format for " + file + "; choose an explicit H2 driver profile"))
.format();
}
private static StoreHeader parseHeader(byte[] fileBytes, int offset) {
byte[] block = java.util.Arrays.copyOfRange(fileBytes, offset, offset + BLOCK_SIZE);
int start = 0;
int end = block.length;View on GitHub (pinned to c0390bff16)
Solutions
- Restore the .mv.db file from backup or re-copy it in full
- Delete the truncated file if it is a leftover from a failed start and let H2 recreate the database
- Check available disk space and re-run the copy with verification (checksum)
Example fix
// before ls -la /data/app.mv.db # 1024 bytes (truncated) // after cp /backups/app.mv.db /data/app.mv.db # full copy, > 8KB
Defensive patterns
Strategy: validation
Validate before calling
Path mv = Path.of(base + ".mv.db");
if (Files.isRegularFile(mv) && Files.size(mv) < 8192) {
throw new IllegalStateException(mv + " is truncated/empty; restore from backup");
} Try / catch
try {
return H2Agent.connect(params);
} catch (IOException e) {
if (e.getMessage().contains("too small to contain valid headers")) {
// restore from backup or remove leftover file
}
throw e;
} Prevention
- Check file sizes after copying/restoring H2 databases
- Monitor disk space to avoid truncated writes
- Treat zero-byte .mv.db files as failed-start artifacts to clean up
When it happens
Trigger: detect() found a .mv.db file but readMvStoreFormat read < 8192 bytes — i.e. the file exists but is truncated, empty, or nearly empty.
Common situations: Zero-byte .mv.db created by a failed H2 startup; copy of the database interrupted mid-transfer; disk-full during a write truncated the file; empty placeholder file created by a script.
Related errors
- Custom H2 JDBC JAR does not exist: " + path
- Unsupported H2 database file format: " + format
- Both H2 PageStore and MVStore files exist for " + base + ";
- H2 JDBC driver was not loaded
- H2 JDBC driver rejected URL: " + buildJdbcUrl(params)
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/5886a066ed2e5ef9.
Report an issue: GitHub.