k3s-io/k3s · error

invalid ip format '%s'

Error message

invalid ip format '%s'

What it means

Inside ParseStringSliceToIPs each input string is split on ',' and every token goes through net.ParseIP; the first token that returns nil (not parseable as IPv4 or IPv6) produces this error naming the offending token. It is also the underlying error surfaced by the 'invalid node-ip' wrapper when parsing node IPs.

Source

Thrown at pkg/util/net.go:184

		name = hostname
	}

	// Use lower case hostname to comply with kubernetes constraint:
	// https://github.com/kubernetes/kubernetes/issues/71140
	name = strings.ToLower(name)

	return name, ips, nil
}

// ParseStringSliceToIPs converts slice of strings that in turn can be lists of comma separated unparsed IP addresses
// into a single slice of net.IP, it returns error if at any point parsing failed
func ParseStringSliceToIPs(s []string) ([]net.IP, error) {
	var ips []net.IP
	for _, unparsedIP := range s {
		for _, v := range strings.Split(unparsedIP, ",") {
			ip := net.ParseIP(v)
			if ip == nil {
				return nil, fmt.Errorf("invalid ip format '%s'", v)
			}
			ips = append(ips, ip)
		}
	}

	return ips, nil
}

// GetFirstValidIPString returns the first valid address from a list of IP address strings,
// without preference for IP family. If no address are found, an empty string is returned.
func GetFirstValidIPString(s []string) string {
	for _, unparsedIP := range s {
		for _, v := range strings.Split(unparsedIP, ",") {
			if ip := net.ParseIP(v); ip != nil {
				return v
			}
		}
	}

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Read the token quoted in the message - it is exactly what failed to parse
  2. Strip empties and whitespace before parsing: strings.TrimSpace on each token, drop zero-length items
  3. Allow only literal IPs in whatever field feeds this API; validate in your config layer with net.ParseIP

Example fix

// before
ips, err := util.ParseStringSliceToIPs(cfg.NodeIPs)
// after
cleaned := []string{}
for _, s := range cfg.NodeIPs {
	for _, tok := range strings.Split(s, ",") {
		if tok = strings.TrimSpace(tok); tok != "" {
			cleaned = append(cleaned, tok)
		}
	}
}
ips, err := util.ParseStringSliceToIPs(cleaned)
Defensive patterns

Strategy: validation

Validate before calling

func CleanIPList(in []string) ([]string, error) {
	out := []string{}
	for _, s := range in {
		for _, tok := range strings.Split(s, ",") {
			tok = strings.TrimSpace(tok)
			if tok == "" {
				continue
			}
			if net.ParseIP(tok) == nil {
				return nil, fmt.Errorf("invalid ip format '%s'", tok)
			}
			out = append(out, tok)
		}
	}
	return out, nil
}

Type guard

func isLiteralIP(s string) bool { return net.ParseIP(s) != nil }

Try / catch

ips, err := util.ParseStringSliceToIPs(list)
if err != nil {
	if strings.Contains(err.Error(), "invalid ip format") {
		// the quoted token in the message is the exact bad value; fix the source list
	}
	return nil, err
}

Prevention

When it happens

Trigger: Calling util.ParseStringSliceToIPs with a typo'd address, an empty token (from 'a,,b' or a trailing comma), a CIDR, or a hostname in the list.

Common situations: Helm/CLI templating emitting empty values (',,'); env var interpolation leaving placeholders like '<nodeIP>'; users pasting '10.0.0.1/24' or a DNS name into an IP-only field.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/fb7b9e6e4a911507. Report an issue: GitHub.