{"record":{"id":"d580f32feb5f5680","repo":"k3s-io/k3s","slug":"invalid-node-external-ip-w","errorCode":null,"errorMessage":"invalid node-external-ip: %w","messagePattern":"invalid node-external-ip: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/agent/config/config.go","lineNumber":505,"sourceCode":"\tif err := os.MkdirAll(nodeConfigPath, 0755); err != nil {\n\t\treturn nil, err\n\t}\n\n\toldNodePasswordFile := filepath.Join(envInfo.DataDir, \"agent\", \"node-password.txt\")\n\tnewNodePasswordFile := filepath.Join(nodeConfigPath, \"password\")\n\tupgradeOldNodePasswordPath(oldNodePasswordFile, newNodePasswordFile)\n\n\tif controlConfig.ClusterIPRange != nil {\n\t\tif utilsnet.IPFamilyOfCIDR(controlConfig.ClusterIPRange) != utilsnet.IPFamilyOf(nodeIPs[0]) && len(nodeIPs) > 1 {\n\t\t\tfirstNodeIP := nodeIPs[0]\n\t\t\tnodeIPs[0] = nodeIPs[1]\n\t\t\tnodeIPs[1] = firstNodeIP\n\t\t}\n\t}\n\n\tnodeExternalIPs, err := util.ParseStringSliceToIPs(envInfo.NodeExternalIP.Value())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid node-external-ip: %w\", err)\n\t}\n\n\tif envInfo.WithNodeID {\n\t\tnodeID, err := ensureNodeID(filepath.Join(nodeConfigPath, \"id\"))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnodeName += \"-\" + nodeID\n\t}\n\n\tos.Setenv(\"NODE_NAME\", nodeName)\n\n\tkubeconfigKubelet := filepath.Join(envInfo.DataDir, \"agent\", \"kubelet.kubeconfig\")\n\tclientKubeProxyCert := filepath.Join(envInfo.DataDir, \"agent\", \"client-kube-proxy.crt\")\n\tclientKubeProxyKey := filepath.Join(envInfo.DataDir, \"agent\", \"client-kube-proxy.key\")\n\tkubeconfigKubeproxy := filepath.Join(envInfo.DataDir, \"agent\", \"kubeproxy.kubeconfig\")\n\tclientK3sControllerCert := filepath.Join(envInfo.DataDir, \"agent\", \"client-\"+version.Program+\"-controller.crt\")\n\tclientK3sControllerKey := filepath.Join(envInfo.DataDir, \"agent\", \"client-\"+version.Program+\"-controller.key\")","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/agent/config/config.go#L487-L523","documentation":"The agent parses envInfo.NodeExternalIP (the --node-external-ip flag, comma-separated) with util.ParseStringSliceToIPs, which accepts bare IP addresses only; if any element fails net.ParseIP the underlying error is wrapped as 'invalid node-external-ip: ...'. CIDRs, hostnames, ranges and empty elements (trailing comma) are all invalid.","triggerScenarios":"--node-external-ip=203.0.113.7/32 (CIDR), --node-external-ip=nat.example.com (hostname), '1.2.3.4,' (trailing comma), whitespace inside elements, or a malformed IPv6 literal.","commonSituations":"Copy/pasting a CIDR from cluster-cidr docs; templates injecting an unset variable leaving stray commas; expecting hostname resolution where none is supported.","solutions":["Pass plain IPs only: --node-external-ip=203.0.113.7 (or a comma-separated list of IPs)","Resolve hostnames to IPs yourself before passing the flag","Strip whitespace and drop empty items from the value"],"exampleFix":"# before\n--node-external-ip=\"203.0.113.7/32,\"\n\n# after\n--node-external-ip=\"203.0.113.7\"","handlingStrategy":"validation","validationCode":"for _, s := range strings.Split(value, \",\") {\n    s = strings.TrimSpace(s)\n    if s == \"\" || net.ParseIP(s) == nil {\n        return fmt.Errorf(\"--node-external-ip accepts bare IPs only, got %q\", s)\n    }\n}","typeGuard":"func validExternalIPs(v string) bool {\n    for _, s := range strings.Split(v, \",\") {\n        if net.ParseIP(strings.TrimSpace(s)) == nil {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Pass bare IPs, never CIDRs or hostnames, to --node-external-ip","Trim whitespace and remove trailing commas in templated flags"],"tags":["config","ip","validation","agent","network"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}