lionsoul2014/ip2region · error · Exception
incomplete read: read bytes should be {$len}
Error message
incomplete read: read bytes should be {$len} What it means
fread() succeeded but returned fewer bytes than requested ($len). A short read on a well-formed xdb means the file is truncated or the offset is past the end, so the library refuses to return partial data.
Source
Thrown at binding/php/xdb/Searcher.class.php:567
// check the in-memory buffer first
if ($this->contentBuff != null) {
return substr($this->contentBuff, $offset, $len);
}
// read from the file
$r = fseek($this->handle, $offset);
if ($r == -1) {
throw new Exception("failed to fseek to {$offset}");
}
$this->ioCount++;
$buff = fread($this->handle, $len);
if ($buff === false) {
throw new Exception("failed to fread from {$len}");
}
if (strlen($buff) != $len) {
throw new Exception("incomplete read: read bytes should be {$len}");
}
return $buff;
}
}
View on GitHub (pinned to c1a1fc7d59)
Solutions
- Re-download/regenerate the xdb file and verify its size and checksum against the source
- Confirm the xdb structure version is compatible with the library version you run (v2/v3)
- Run the library's structure verification (e.g. util verify) against the file before searching
Example fix
// before
$searcher = ...newWithFileOnly('/path/truncated.xdb');
// after
// re-copy full file, then verify:
$searcher = ...newWithFileOnly('/path/full.xdb');
// or check: filesize($dbFile) matches the publisher's expected size Defensive patterns
Strategy: validation
Validate before calling
$expected = 11; // check header/expected size from your xdb source
if (filesize($dbFile) < $expected) {
throw new RuntimeException("xdb file truncated: {$dbFile}");
} Try / catch
try {
$region = $searcher->search($ip);
} catch (\Exception $e) {
if (strpos($e->getMessage(), 'incomplete read') !== false) {
// file truncated/corrupt: re-fetch the xdb and rebuild the searcher
$region = null;
} else {
throw $e;
}
} Prevention
- Verify the xdb file size/checksum after download or deploy
- Do not truncate copies with scp/ftp interruptions; use atomic replace
- Keep searcher and xdb structure versions in sync
When it happens
Trigger: search()/read() where strlen($buff) != $len — reading past EOF because the xdb file is truncated/corrupted, or the data was written by an incompatible structure version.
Common situations: Partially downloaded or interrupted copy of the xdb file; wrong xdb file version paired with a newer/older searcher; file replaced mid-search with a smaller file.
Related errors
- failed to fseek to {$offset}
- failed to fread from {$len}
- incomplete read (${rBytes} read, ${header.HeaderInfoLength}
- incomplete read (${rBytes} read, ${vBytes} expected)
- incomplete read (${rBytes} read, ${stats.size} expected)
AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02).
Data as JSON: /api/errors/078140efcf66f480.
Report an issue: GitHub.