lionsoul2014/ip2region · error · IOException
incomplete read: read bytes should be ${len}
Error message
incomplete read: read bytes should be ${len} What it means
loadVectorIndex reads VectorIndexRows*VectorIndexCols*VectorIndexSize bytes starting at HeaderInfoLength and requires a single full read. A short read means the xdb file is smaller than a valid structure or IO failed, so an IOException is thrown.
Source
Thrown at binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java:244
}
public static Header loadHeaderFromFile(String xdbPath) throws IOException {
return loadHeaderFromFile(new File(xdbPath));
}
public static Header loadHeaderFromBuffer(LongByteArray cBuffer) throws IOException {
return new Header(cBuffer.slice(0, HeaderInfoLength));
}
// --- read xdb vector index
public static byte[] loadVectorIndex(RandomAccessFile handle) throws IOException {
handle.seek(HeaderInfoLength);
int len = VectorIndexRows * VectorIndexCols * VectorIndexSize;
final byte[] buff = new byte[len];
int rLen = handle.read(buff);
if (rLen != len) {
throw new IOException("incomplete read: read bytes should be " + len);
}
return buff;
}
public static byte[] loadVectorIndexFromFile(File xdbFile) throws IOException {
final RandomAccessFile handle = new RandomAccessFile(xdbFile, "r");
final byte[] vIndex = loadVectorIndex(handle);
handle.close();
return vIndex;
}
public static byte[] loadVectorIndexFromFile(String xdbPath) throws IOException {
return loadVectorIndexFromFile(new File(xdbPath));
}
public static byte[] loadVectorIndexFromBuffer(LongByteArray cBuffer) throws IOException {
final int len = VectorIndexRows * VectorIndexCols * VectorIndexSize;View on GitHub (pinned to c1a1fc7d59)
Solutions
- Re-download or re-copy a complete xdb file and check its size matches the original
- Call Searcher.verify(raf) before building the searcher to detect bad files early
- Use atomic file publication (write temp file, then rename) so readers never see partial files
Example fix
// before
byte[] vIndex = Searcher.loadVectorIndexFromFile(new File("partial.xdb"));
// after
RandomAccessFile raf = new RandomAccessFile("full.xdb", "r");
Searcher.verify(raf); // throws XdbException on bad files
byte[] vIndex = Searcher.loadVectorIndex(raf); Defensive patterns
Strategy: validation
Validate before calling
File f = new File(xdbFile);
if (f.length() < 256 + 256*256*4) throw new IllegalStateException("xdb too small for vector index");
Searcher.verify(new RandomAccessFile(f, "r")); Try / catch
try {
byte[] vIndex = Searcher.loadVectorIndexFromFile(f);
} catch (IOException e) {
log.error("failed to load vector index, falling back to file mode", e);
vIndex = null;
} Prevention
- Check file size against the official release before loading
- Download with checksum verification and atomic rename
- Run Searcher.verify once at startup for every xdb asset
When it happens
Trigger: Calling Searcher.loadVectorIndex(handle)/loadVectorIndexFromFile on a truncated xdb file (less than 256+vector-index bytes) or on a partially copied/downloaded file.
Common situations: Incomplete uploads of the xdb to servers/containers; using an empty placeholder file; corrupted cache of the xdb in CI.
Related errors
- incomplete read: read bytes should be ${buffer.length}
- incomplete read: read bytes should be ${buff.length}, got `$
- ip verison not match: xdb file ${xdbFile.getAbsolutePath()}
- invalid cache policy `${name}`
- SetXdbInputStream could ONLY be used with cachePolicy = Conf
AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02).
Data as JSON: /api/errors/52b7a38721fff948.
Report an issue: GitHub.