k3s-io/k3s · error
invalid node IP address %s
Error message
invalid node IP address %s
What it means
The kubelet serving-cert signing endpoint (pkg/server/handlers/handlers.go) authenticates the requesting node and builds a SAN list from the k3s-Node-IP request header (comma-separated). Each comma-separated value must parse with net.ParseIP; any unparseable value produces this 400 error before a cert is signed. Note the message formats the already-nil parsed value, so it renders as 'invalid node IP address <nil>' rather than showing the bad input.
Source
Thrown at pkg/server/handlers/handlers.go:75
resp.Header().Set("Content-Length", strconv.Itoa(len(data)))
resp.Write(data)
})
}
func ServingKubeletCert(control *config.Control, auth nodepassword.NodeAuthValidator) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
nodeName, errCode, err := auth(req)
if err != nil {
util.SendError(err, resp, req, errCode)
return
}
ips := []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")}
if nodeIP := req.Header.Get(version.Program + "-Node-IP"); nodeIP != "" {
for _, v := range strings.Split(nodeIP, ",") {
ip := net.ParseIP(v)
if ip == nil {
util.SendError(fmt.Errorf("invalid node IP address %s", ip), resp, req)
return
}
ips = append(ips, ip)
}
}
signAndSend(resp, req, control.Runtime.ServerCA, control.Runtime.ServerCAKey, control.Runtime.ServingKubeletKey, certutil.Config{
CommonName: nodeName,
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
AltNames: certutil.AltNames{
DNSNames: []string{nodeName, "localhost"},
IPs: ips,
},
})
})
}
func ClientKubeletCert(control *config.Control, auth nodepassword.NodeAuthValidator) http.Handler {View on GitHub (pinned to 6ba341e396)
Solutions
- Inspect the agent's flags and correct --node-ip to literal IP addresses only (valid IPv4 or IPv6), no hostnames, ports, brackets, or empty segments.
- If multiple IPs are needed, keep the comma list strict: exactly one address per element, no trailing comma or spaces.
- Restart the k3s agent so it re-registers with the fixed header.
- If templating from config management, assert the value matches an IP regex before deploying.
Example fix
# before k3s agent --server https://server:6443 --node-ip mynode.example.com, # after k3s agent --server https://server:6443 --node-ip 10.0.0.5
Defensive patterns
Strategy: validation
Validate before calling
// Agent-side: validate --node-ip before k3s uses it
for _, s := range strings.Split(nodeIPFlag, ",") {
if net.ParseIP(strings.TrimSpace(s)) == nil {
log.Fatalf("invalid --node-ip value %q", s)
}
} Type guard
func validNodeIPList(v string) bool {
if v == "" { return true }
for _, s := range strings.Split(v, ",") {
if net.ParseIP(s) == nil { return false }
}
return true
} Prevention
- Pass only literal IPs (no hostnames, ports, brackets) to --node-ip
- Lint templated agent configs that interpolate node IP variables
- Avoid trailing commas and whitespace in multi-IP lists
When it happens
Trigger: An agent (or direct HTTP caller) hits /v1-k3s/serving-kubelet-cert with a k3s-Node-IP header containing a value that net.ParseIP rejects: a hostname, a value with whitespace or a port (e.g. 10.0.0.1:10250), an IPv6 with brackets, or an empty string produced by a trailing/duplicated comma.
Common situations: Setting --node-ip with a DNS name or malformed address on k3s agent; shell quoting that appends a stray comma ('--node-ip 10.0.0.1,'); scripts templating the flag from an empty variable; IPv6 addresses passed with surrounding brackets because they came from a URL.
Related errors
- invalid node-external-ip: %w
- cluster-cidr: %v and service-cidr: %v, must share the same I
- failed to read http config %s: %w
- value required for kubelet-arg --%s
- all servers failed
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/ecd2212e3168bbae.
Report an issue: GitHub.