lionsoul2014/ip2region · error · IOException

incomplete read: read bytes should be ${buff.length}, got `$

Error message

incomplete read: read bytes should be ${buff.length}, got `${rLen}`

What it means

loadContent copies the entire xdb into a LongByteArray in slices; each handle.read must fill the whole slice. A short read (rLen != buff.length, including -1 at EOF) indicates the file ended prematurely or IO failed mid-copy, so an IOException with both expected and actual byte counts is thrown.

Source

Thrown at binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java:283

    // --- read xdb content

    // -- load xdb buffer with random access file handle
    
    public static LongByteArray loadContent(RandomAccessFile handle) throws IOException {
        return loadContent(handle, DEFAULT_SLICE_BYTES);
    }

    public static LongByteArray loadContent(RandomAccessFile handle, final int sliceBytes) throws IOException {
        handle.seek(0);
        // check the length and do the buff load
        long toRead = handle.length();
        final LongByteArray byteArray = new LongByteArray(sliceBytes);
        while (toRead > 0) {
            final byte[] buff = new byte[(int) Math.min(toRead, sliceBytes)];
            final int rLen = handle.read(buff);
            if (rLen != buff.length) {
                throw new IOException("incomplete read: read bytes should be " + buff.length + ", got `" + rLen + "`");
            }

            byteArray.append(buff);
            toRead -= rLen;
        }

        return byteArray;
    }

    // -- load xdb buffer with xdb file object

    public static LongByteArray loadContentFromFile(File xdbFile) throws IOException {
        return loadContentFromFile(xdbFile, DEFAULT_SLICE_BYTES);
    }

    public static LongByteArray loadContentFromFile(File xdbFile, final int sliceBytes) throws IOException {
        final RandomAccessFile handle = new RandomAccessFile(xdbFile, "r");
        final LongByteArray content = loadContent(handle, sliceBytes);

View on GitHub (pinned to c1a1fc7d59)

Solutions

  1. Verify the xdb file size and checksum against the official release and replace the file if wrong
  2. Run Searcher.verify on the file before loading content
  3. Re-download the xdb with retry/atomic rename to avoid partial files
  4. Check disk space and storage health if the failure is transient

Example fix

// before
byte[] buf = Searcher.loadContent(raf, 8192); // raf file truncated
// after
if (raf.length() < officialXdbSize) {
    throw new IllegalStateException("xdb truncated, re-download");
}
byte[] buf = Searcher.loadContent(raf, 8192);
Defensive patterns

Strategy: validation

Validate before calling

if (raf.length() < expectedXdbSize) {
    throw new IllegalStateException("xdb truncated: " + raf.length() + " < " + expectedXdbSize);
}

Try / catch

try {
    byte[] content = Searcher.loadContent(raf, sliceBytes);
} catch (IOException e) {
    log.error("content load short-read; re-fetching xdb", e);
    content = redownloadAndLoad();
}

Prevention

When it happens

Trigger: Calling Searcher.loadContent (or the content cachePolicy constructor path) on a truncated xdb file, or a read error occurring mid-file on unstable storage.

Common situations: xdb download interrupted by network failure; container image built with an incompletely copied asset; disk full/IO faults on the host.

Related errors


AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02). Data as JSON: /api/errors/c70c19dec2b45f4d. Report an issue: GitHub.