OpenNHP/opennhp · error

invalid IP address

Error message

invalid IP address: %s

What it means

DetectIPType in nhp/utils/iputils.go parses an IP string with net.ParseIP to classify it as IPv4 or IPv6. If parsing fails (nil), it returns this error instead of a type. It is a strict input-validation guard used by access-control handlers.

Solutions

  1. Strip port and CIDR suffixes before calling (net.SplitHostPort, strings.Cut on '/')
  2. Resolve hostnames with net.LookupHost if names are expected
  3. Validate with net.ParseIP at the config-load boundary and fail fast with a field name in the message
  4. Trim whitespace

Example fix

// before
ipType, err := DetectIPType("10.0.0.1:8080")
// after
host, _, _ := net.SplitHostPort("10.0.0.1:8080")
ipType, err := DetectIPType(host)
Defensive patterns

Strategy: validation

Validate before calling

func normalizeIP(raw string) (string, error) {
  s := strings.TrimSpace(raw)
  if h, _, err := net.SplitHostPort(s); err == nil { s = h }
  if i, _, err := net.ParseCIDR(s); err == nil { s = i.String() }
  if net.ParseIP(s) == nil { return "", fmt.Errorf("not an IP: %q", raw) }
  return s, nil
}

Try / catch

ipType, err := DetectIPType(s); if err != nil { return fmt.Errorf("classify ip %q: %w", s, err) }

Prevention

When it happens

Trigger: Calling DetectIPType with a non-IP string: hostname ('example.com'), empty string, malformed address ('1.2.3', '300.1.1.1'), CIDR notation ('10.0.0.0/8'), or an address with port ('10.0.0.1:8080').

Common situations: Extracting client IPs from headers and including port or bracket syntax ('[::1]:8080'); config fields holding DNS names; log-parsing pipelines feeding raw tokens in.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/c32a8c0e7b8608ce. Report an issue: GitHub.

Appendix: source

Thrown at nhp/utils/iputils.go:21

import (
	"fmt"
	"net"
)

// CIDR mask constants for IP address handling
const (
	IPv4SingleHost    = "/32"  // Single IPv4 host
	IPv4AdjacentRange = "/25"  // 128 IPv4 addresses
	IPv6SingleHost    = "/128" // Single IPv6 host
	IPv6AdjacentRange = "/121" // 128 IPv6 addresses (equivalent to IPv4 /25)
)

// DetectIPType parses an IP address string and returns whether it's IPv4 or IPv6.
// Returns an error if the IP address is invalid.
func DetectIPType(ipStr string) (IPTYPE, error) {
	ip := net.ParseIP(ipStr)
	if ip == nil {
		return 0, fmt.Errorf("invalid IP address: %s", ipStr)
	}
	if ip.To4() != nil {
		return IPV4, nil
	}
	return IPV6, nil
}

// IsIPv6 returns true if the string is a valid IPv6 address.
// Note: IPv4-mapped IPv6 addresses (::ffff:x.x.x.x) return false because
// Go's net.IP.To4() returns a non-nil value for these addresses.
func IsIPv6(ipStr string) bool {
	ip := net.ParseIP(ipStr)
	return ip != nil && ip.To4() == nil
}

// IsIPv4 returns true if the string is a valid IPv4 address.
func IsIPv4(ipStr string) bool {
	ip := net.ParseIP(ipStr)

View on GitHub (pinned to 6e04ca5ff0)