{"record":{"id":"73f8fbad18b5739c","repo":"lionsoul2014/ip2region","slug":"invalid-ip-address-version-name-expected","errorCode":null,"errorMessage":"invalid ip address (${version.name} expected)","messagePattern":"invalid ip address \\((.+?) expected\\)","errorType":"validation","errorClass":"InetAddressException","httpStatus":null,"severity":"error","filePath":"binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java","lineNumber":115,"sourceCode":"        }\n    }\n\n    public Version getIPVersion() {\n        return version;\n    }\n\n    public int getIOCount() {\n        return ioCount;\n    }\n\n    public String search(String ipStr) throws Exception {\n        return search(Util.parseIP(ipStr));\n    }\n\n    public String search(byte[] ip) throws IOException, InetAddressException {\n        // ip version check\n        if (ip.length != version.bytes) {\n            throw new InetAddressException(\"invalid ip address (\"+version.name+\" expected)\");\n        }\n\n        // reset the global counter\n        this.ioCount = 0;\n\n        // locate the segment index block based on the vector index\n        long sPtr = 0, ePtr = 0;\n        int il0 = (int) (ip[0] & 0xFF);\n        int il1 = (int) (ip[1] & 0xFF);\n        int idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize;\n        // System.out.printf(\"il0: %d, il1: %d, idx: %d\\n\", il0, il1, idx);\n        if (vectorIndex != null) {\n            sPtr = LittleEndian.getUint32(vectorIndex, idx);\n            ePtr = LittleEndian.getUint32(vectorIndex, idx + 4);\n        } else if (contentBuff != null) {\n            sPtr = contentBuff.getUint32(HeaderInfoLength + idx);\n            ePtr = contentBuff.getUint32(HeaderInfoLength + idx + 4);\n        } else {","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/lionsoul2014/ip2region/blob/c1a1fc7d5941760db3f8431dc05c48cf7f0e30a1/binding/java/src/main/java/org/lionsoul/ip2region/xdb/Searcher.java#L97-L133","documentation":"Xdb Searcher instances are version-bound: a V4 searcher only accepts byte[4] IPs and a V6 searcher only byte[16]. The public search(byte[]) checks ip.length against version.bytes and throws InetAddressException when the IP version does not match the searcher's xdb version.","triggerScenarios":"Calling search on a searcher built via asV4() with a 16-byte IPv6 array, or via asV6() with a 4-byte IPv4 array.","commonSituations":"Dual-stack applications routing all incoming addresses through a single V4 searcher; using the wrong Ip2Region field (v4 vs v6) after a code refactor.","solutions":["Route the IP to the searcher matching its version: ip.length==4 -> v4 searcher, ip.length==16 -> v6 searcher","Use Ip2Region.search(String) or a length check on the raw bytes to pick the correct searcher","Create/keep both a V4 and a V6 searcher and dispatch on array length"],"exampleFix":"// before\nString r = v6Searcher.search(ipBytes); // ipBytes.length == 4\n// after\nString r = (ipBytes.length == 4) ? v4Searcher.search(ipBytes) : v6Searcher.search(ipBytes);","handlingStrategy":"type-guard","validationCode":"if (ip.length != expectedVersionBytes) {\n    throw new IllegalArgumentException(\"searcher version mismatch\");\n}","typeGuard":"static boolean matchesSearcherVersion(byte[] ip, Version v) {\n    return ip != null && ip.length == v.bytes;\n}","tryCatchPattern":"try {\n    return searcher.search(ip);\n} catch (InetAddressException e) {\n    log.warn(\"ip version mismatch for searcher\", e);\n    return alternateSearcher(ip);\n}","preventionTips":["Keep both v4 and v6 searchers and dispatch on ip.length","Never share one Searcher across dual-stack traffic","Name variables explicitly (v4Searcher/v6Searcher) to avoid wiring mistakes"],"tags":["java","ip-address","version-mismatch"],"backgroundTag":"ip-version-mismatch","analyzedSha":"c1a1fc7d5941760db3f8431dc05c48cf7f0e30a1","analyzedAt":"2026-09-02T16:58:39.988Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}