lionsoul2014/ip2region · error
invalid ip address(%s expected)
Error message
invalid ip address(%s expected)
What it means
After parsing, Search verifies the byte length of the IP matches the searcher's xdb version (4 bytes for IPv4, 16 for IPv6). A mismatch — e.g. an IPv4 address searched against an IPv6 xdb — returns this error naming the expected version.
Source
Thrown at binding/golang/xdb/searcher.go:128
// Search the region for the specified string or bytes ip address
func (s *Searcher) Search(ip any) (string, error) {
var err error
var ipBytes []byte
switch v := ip.(type) {
case string:
ipBytes, err = ParseIP(v)
if err != nil {
return "", fmt.Errorf("parse ip %s: %w", v, err)
}
case []byte:
ipBytes = v
default:
return "", fmt.Errorf("invalid ip value type %s", v)
}
// ip version check
if len(ipBytes) != s.version.Bytes {
return "", fmt.Errorf("invalid ip address(%s expected)", s.version.Name)
}
// reset the global ioCount
s.ioCount = 0
// locate the segment index block based on the vector index
var il0, il1 = int(ipBytes[0]), int(ipBytes[1])
var idx = il0*VectorIndexCols*VectorIndexSize + il1*VectorIndexSize
var sPtr, ePtr = uint32(0), uint32(0)
if s.vectorIndex != nil {
sPtr = binary.LittleEndian.Uint32(s.vectorIndex[idx:])
ePtr = binary.LittleEndian.Uint32(s.vectorIndex[idx+4:])
} else if s.contentBuff != nil {
sPtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx:])
ePtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx+4:])
} else {
// read the vector index block
var buff = make([]byte, VectorIndexSize)View on GitHub (pinned to c1a1fc7d59)
Solutions
- Load the matching xdb file version for your input (xdb_v4 for IPv4 IPs, xdb_v6 for IPv6).
- Detect the IP family first (len of net.ParseIP(ip).To4()==4) and route to the appropriate searcher.
- Normalize with To4()/To16() so the byte length always matches the searcher's version.
- Use IPVersion from the header (via LoadHeader) to pick the right searcher automatically.
Example fix
// before
region, err := v6Searcher.Search(ctx, "1.2.3.4") // wrong family
// after
ip := net.ParseIP("1.2.3.4")
if ip.To4() != nil {
region, err = v4Searcher.Search(ctx, ip.String())
} else {
region, err = v6Searcher.Search(ctx, ip.String())
} Defensive patterns
Strategy: validation
Validate before calling
ip := net.ParseIP(raw)
ipBytes := ip.To4()
if ipBytes == nil { ipBytes = ip.To16() }
want := 16
if header.IPVersion == xdb.IPv4 { want = 4 }
if len(ipBytes) != want {
return fmt.Errorf("ip family mismatch: got %d bytes, xdb expects %d", len(ipBytes), want)
} Type guard
func matchesXDBVersion(raw string, ver xdb.IPVersion) bool {
ip := net.ParseIP(raw)
if ip == nil { return false }
if ver == xdb.IPv4 { return ip.To4() != nil }
return ip.To4() == nil
} Try / catch
region, err := searcher.Search(ctx, raw)
if err != nil && strings.Contains(err.Error(), "invalid ip address(") {
// route to the other-version searcher or drop the record
return handleVersionMismatch(raw, err)
} Prevention
- Load both xdb_v4 and xdb_v6 and route by IP family.
- Check the header's IPVersion at startup and log the expected family.
- Normalize with To4()/To16() before searching by bytes.
- Test with both an IPv4 and IPv6 sample in CI.
When it happens
Trigger: Searching "1.2.3.4" against an xdb_v6.xdb (or an IPv6 literal against an xdb_v4.xdb); passing a 4-byte slice where 16 bytes are required, or vice versa; passing an unexpanded IPv4-mapped form with wrong length.
Common situations: Mixing v4 and v6 xdb files in one app and reusing one searcher for all inputs; log data mixing IPv4 and IPv6 addresses; using To4() output on an IPv6 searcher.
Related errors
- invalid bytes ip with length not 4 or 16
- ip verison not match: xdb file ${xdbFile.getAbsolutePath()}
- invalid ip address ({$this->version->name} expected)
- invalid ip address `{}` ({} expected)
- invalid input buffer
AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02).
Data as JSON: /api/errors/d44425e9f10a6baf.
Report an issue: GitHub.