lionsoul2014/ip2region · error · Exception

invalid ip address ({$this->version->name} expected)

Error message

invalid ip address ({$this->version->name} expected)

What it means

The PHP Searcher throws this when the byte length of the IP passed to searchByBytes() does not match the byte count required by the xdb file's IP version (e.g. 4 bytes for IPv4, 16 for IPv6). The library checks the version up front because searching with the wrong IP size would corrupt index lookups.

Source

Thrown at binding/php/xdb/Searcher.class.php:483

     */
    public function search($ip) {
        $ipBytes = Util::parseIP($ip);
        if ($ipBytes == null) {
            throw new Exception("invalid ip address `{$ip}`");
        }

        return $this->searchByBytes($ipBytes);
    }

    /**
     * find the region info for the specified binary ip bytes returned by #parseIP.
     * 
     * @throws Exception
     */
    public function searchByBytes($ipBytes) {
        // ip version check
        if (strlen($ipBytes) != $this->version->bytes) {
            throw new Exception("invalid ip address ({$this->version->name} expected)");
        }

        // reset the global counter
        $this->ioCount = 0;

        // locate the segment index block based on the vector index
        $il0 = ord($ipBytes[0]) & 0xFF;
        $il1 = ord($ipBytes[1]) & 0xFF;
        $idx = $il0 * VectorIndexCols * VectorIndexSize + $il1 * VectorIndexSize;
        if ($this->vectorIndex != null) {
            $sPtr = Util::le_getUint32($this->vectorIndex, $idx);
            $ePtr = Util::le_getUint32($this->vectorIndex, $idx + 4);
        } else if ($this->contentBuff != null) {
            $sPtr = Util::le_getUint32($this->contentBuff, HeaderInfoLength + $idx);
            $ePtr = Util::le_getUint32($this->contentBuff, HeaderInfoLength + $idx + 4);
        } else {
            // read the vector index block
            $buff = $this->read(HeaderInfoLength + $idx, 8);

View on GitHub (pinned to c1a1fc7d59)

Solutions

  1. Convert the IP string to raw bytes with the library's helper (e.g. inet_pton / util parse) before calling searchByBytes()
  2. Verify the xdb file's IP version matches the addresses you search; load an IPv6-capable (v3) xdb if you need IPv6
  3. Use the higher-level search($ip) entry point which parses and validates the IP string for you

Example fix

// before
$searcher->searchByBytes('1.2.3.4');
// after
$bytes = inet_pton('1.2.3.4'); // 4 raw bytes for IPv4
$searcher->searchByBytes($bytes);
Defensive patterns

Strategy: validation

Validate before calling

$bytes = is_string($ip) ? (filter_var($ip, FILTER_VALIDATE_IP) ? inet_pton($ip) : null) : $ip;
if ($bytes === null || strlen($bytes) !== $this->version->bytes) {
    throw new InvalidArgumentException("ip does not match {$this->version->name}");
}

Type guard

function isIpBytesFor(string $bytes, object $version): bool {
    return strlen($bytes) === $version->bytes;
}

Try / catch

try {
    $region = $searcher->searchByBytes($bytes);
} catch (\Exception $e) {
    if (strpos($e->getMessage(), 'invalid ip address') !== false) {
        $region = null; // treat as unresolvable input
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Calling Searcher::searchByBytes() with a byte string whose strlen() differs from $this->version->bytes — e.g. passing 16-byte IPv6 bytes to a v4-only xdb searcher, or 4-byte bytes to a v6 searcher, or a non-raw binary string.

Common situations: Opening an IPv4 xdb file but searching IPv6 addresses (or vice versa); passing a hex/human-readable string like '1.2.3.4' instead of the packed 4-byte form; mixing up a v1 (IPv4) file with the v3 (IPv6-capable) searcher API.

Related errors


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