lionsoul2014/ip2region · warning
IPSub(%s, %s): %w
Error message
IPSub(%s, %s): %w
What it means
IPMiddle computes the midpoint of two IPs and calls IPAdd internally; if IPAdd fails (e.g. length mismatch), the error is wrapped as IPSub(%s, %s): %w with both IPs stringified. Note the message says IPSub but the failing call is IPAdd — the wrap is mislabeled.
Source
Thrown at binding/golang/xdb/util.go:132
var carry byte = 0
for i := 0; i < length; i++ {
// 1. Shift current byte right by 1
// 2. Or (|) with the carry from the previous byte (shifted to the MSB position)
result[i] = (ip[i] >> 1) | (carry << 7)
// 3. Capture the Least Significant Bit (LSB) to use as carry for the next byte
carry = ip[i] & 1
}
return result
}
// IPMiddle get the middle value of two input ip address
func IPMiddle(sip, eip []byte) ([]byte, error) {
buf, err := IPAdd(sip, eip)
if err != nil {
return []byte{}, fmt.Errorf("IPSub(%s, %s): %w", IP2String(sip), IP2String(eip), err)
}
return IPHalf(buf), nil
}
// Verify if the current Searcher could be used to search the specified xdb file.
// Why do we need this check ?
// The future features of the xdb impl may cause the current searcher not able to work properly.
//
// @Note: You Just need to check this ONCE when the service starts
// Or use another process (eg, A command) to check once Just to confirm the suitability.
func Verify(handle *os.File) error {
header, err := LoadHeader(handle)
if err != nil {
return fmt.Errorf("loading header: %w", err)
}
// get the runtime ptr bytesView on GitHub (pinned to c1a1fc7d59)
Solutions
- Make both inputs the same byte length (both To4 or both To16) before calling IPMiddle
- Read the wrapped %w error — it will be "length of the two ips are not the same" from IPAdd
- Ensure the sip <= eip pair belongs to the same IP version in your range data
- Ignore the misleading IPSub prefix; it is a known labeling quirk in this code path
Example fix
// before
m, err := xdb.IPMiddle(sip4, eip6) // IPSub(...): length of the two ips are not the same
// after
if len(sip4) != len(eip6) { return errors.New("range spans v4/v6") }
mid, err := xdb.IPMiddle(net.IP(sip4).To16(), net.IP(eip6).To16()) Defensive patterns
Strategy: type-guard
Validate before calling
func canIPMiddle(sip, eip []byte) bool {
return len(sip) == len(eip) && len(sip) > 0
} Type guard
func isSameFamily(sip, eip []byte) bool {
return len(sip) > 0 && len(sip) == len(eip)
} Try / catch
mid, err := xdb.IPMiddle(sip, eip)
if err != nil {
// note: wrapped error mentions IPSub but originates from IPAdd
return fmt.Errorf("ip middle (%d/%d bytes): %w", len(sip), len(eip), err)
} Prevention
- Ensure both operands use the same encoding width before calling IPMiddle
- Remember the IPSub prefix in the message is a mislabel; inspect the wrapped %w cause
- Only call IPMiddle within a single IP-version range
When it happens
Trigger: Calling IPMiddle with a 4-byte and a 16-byte IP; passing empty slices (length 0 vs 0 passes, but 0 vs non-0 fails); calling with IPs from different address families.
Common situations: Splitting IP ranges from a data file that contains both v4 and v6 segments; refactoring code that changed one operand to To16 but not the other; unit tests feeding heterogeneous slices.
Related errors
- invalid ip address: %s
- length of the two ips are not the same
- invalid byte ip address with length=${ipBytes.length}
- invalid ip address (${version.name} expected)
- invalid ip address `${ip}`
AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02).
Data as JSON: /api/errors/cc78fed100201c52.
Report an issue: GitHub.