lionsoul2014/ip2region · error · ValueError
invalid ip address `{}` ({} expected)
Error message
invalid ip address `{}` ({} expected) What it means
search() also validates the IP version: if the parsed bytes' length (4 for IPv4, 16 for IPv6) differs from the xdb structure's byte_num, the address cannot be looked up in this file and ValueError is raised, naming the IP and the expected version.
Source
Thrown at binding/python/ip2region/searcher.py:49
def get_ip_version(self):
return self.version
def get_io_count(self):
return self.__io_count
def search(self, ip: Union[bytes, str]):
# check and parse the string ip
ip_bytes = None
if isinstance(ip, str):
ip_bytes = util.parse_ip(ip)
elif isinstance(ip, bytes):
ip_bytes = ip
else:
raise ValueError("invalid ip address `{}`".format(ip))
# ip version check
if len(ip_bytes) != self.version.byte_num:
raise ValueError("invalid ip address `{}` ({} expected)".format(
util.ip_to_string(ip_bytes), self.version.name))
# reset the global io_count
self.__io_count = 0
# located the segment index block based on the vector index
s_ptr, e_ptr, i0, i1 = 0, 0, ip_bytes[0], ip_bytes[1]
idx = i0 * util.VectorIndexCols * util.VectorIndexSize + i1 * util.VectorIndexSize
if self.vector_index != None:
s_ptr = util.le_get_uint32(self.vector_index, idx)
e_ptr = util.le_get_uint32(self.vector_index, idx + 4)
elif self.c_buffer != None:
offset = util.HeaderInfoLength + idx
s_ptr = util.le_get_uint32(self.c_buffer, offset)
e_ptr = util.le_get_uint32(self.c_buffer, offset + 4)
else:
buff = self.read(util.HeaderInfoLength + idx, util.VectorIndexSize)
s_ptr = util.le_get_uint32(buff, 0)View on GitHub (pinned to c1a1fc7d59)
Solutions
- Load an xdb file whose IP version matches your addresses (v3/IPv6-capable file for IPv6 lookups)
- Check the address family with util.ip_to_string/ipaddress before searching and route v4/v6 to the right searcher
- When passing raw bytes, ensure exactly 4 bytes (v4) or 16 bytes (v6)
Example fix
# before
searcher = Searcher.new_with_file_only(dbfile='ip2region.xdb') # v4 file
searcher.search('::ffff:1.2.3.4')
# after
searcher6 = Searcher.new_with_file_only(dbfile='ip2region_v6.xdb')
searcher6.search('::ffff:1.2.3.4') Defensive patterns
Strategy: validation
Validate before calling
import ipaddress
def pick_searcher(ip: str):
version = ipaddress.ip_address(ip).version
return searcher_v6 if version == 6 else searcher_v4 Type guard
def matches_searcher_version(ip_bytes: bytes, searcher) -> bool:
return len(ip_bytes) == searcher.version.byte_num Try / catch
try:
region = searcher.search(ip)
except ValueError as e:
if '{} expected'.format(searcher.version.name) in str(e):
region = None # wrong family for this xdb
else:
raise Prevention
- Detect the xdb file's IP version at load time and tag the searcher
- Route v4 and v6 traffic to their matching xdb files
- When passing raw bytes, assert len in (4, 16) first
When it happens
Trigger: Searching an IPv6 address (16 bytes) against an IPv4 (v2 structure) xdb, or an IPv4 address against an IPv6/v3 xdb; passing bytes of the wrong length directly.
Common situations: App migrated to IPv6 traffic but still ships the old IPv4-only xdb; loading the wrong file for the searcher version; manually constructing bytes with the wrong length.
Related errors
- invalid ip address (${version.name} expected)
- invalid ip address ({$this->version->name} expected)
- invalid ip address `{}`
- invalid ip address `{}`
- invalid bytes ip `{}`
AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02).
Data as JSON: /api/errors/5dfbc0869039d945.
Report an issue: GitHub.