kubernetes/kops · error

unable to convert CIDR subnet new bits to int: %q: %v

Error message

unable to convert CIDR subnet new bits to int: %q: %v

What it means

ParseCIDRNotation in upup/pkg/fi/utils/net.go parses expanded IPv6 CIDR notation strings of the form <prefix>:<newbits>:<netnum>. The middle segment (new bits) must be a valid decimal integer; when strconv.Atoi on that segment fails, this error is returned with the offending segment and the underlying strconv error.

Source

Thrown at upup/pkg/fi/utils/net.go:90

	if ip.To4() != nil {
		return false
	}

	return true
}

// ParseCIDRNotation parses a string in the format "/<newSize>#<netNum>"
// and returns the values of <newSize> and <netNum>.
func ParseCIDRNotation(subnet string) (int, int64, error) {
	re := regexp.MustCompile(`^/(\d+)#([a-f0-9]+)$`)
	s := re.FindStringSubmatch(subnet)
	if len(s) != 3 {
		return 0, 0, fmt.Errorf("unable to parse CIDR subnet string %q using %q", subnet, re)
	}

	newSize, err := strconv.Atoi(s[1])
	if err != nil {
		return 0, 0, fmt.Errorf("unable to convert CIDR subnet new bits to int: %q: %v", s[1], err)
	}

	netNum, err := strconv.ParseInt(s[2], 16, 64)
	if err != nil {
		return 0, 0, fmt.Errorf("unable to convert CIDR subnet net num to int: %q: %v", s[2], err)
	}

	return newSize, netNum, nil
}

// CIDRSubnet calculates a subnet address within given IP network address prefix.
// Inspired by the Terraform implementation of the "cidrsubnet" function
// https://www.terraform.io/docs/language/functions/cidrsubnet.html
func CIDRSubnet(prefix string, newSize int, netNum int64) (string, error) {
	_, baseCIDR, err := net.ParseCIDR(prefix)
	if err != nil {
		return "", fmt.Errorf("unable to parse CIDR for %q: %v", prefix, err)
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Fix the CIDR-subnet string so the middle segment is a valid decimal integer (e.g. "2001:db8:0000::/48:0:0" style <prefix>:<newbits>:<netnum>).
  2. Confirm the string matches the three-segment format expected by ParseCIDRNotation (regex splits into 3 parts separated by ':').
  3. Validate user/cluster-spec input before calling, e.g. with strconv.Atoi on the middle segment yourself to get a clearer message.
  4. Strip whitespace or stray characters (signs, units) from the segment before parsing.

Example fix

// before
cidr := "2001:db8:0000::/48x:0" // '48x' is not an integer
newSize, netNum, err := utils.ParseCIDRNotation(cidr)
// after
cidr := "2001:db8:0000::/48:0"
newSize, netNum, err := utils.ParseCIDRNotation(cidr)
Defensive patterns

Strategy: validation

Validate before calling

func validNewBits(notation string) bool {
	parts := strings.Split(notation, ":")
	if len(parts) != 3 {
		return false
	}
	_, err := strconv.Atoi(parts[1])
	return err == nil
}

Prevention

When it happens

Trigger: Calling ParseCIDRNotation (directly or via validateIPv6CIDR, RenderTerraform, or calculateSubnetCIDR) with a CIDR-subnet string whose middle segment is not a decimal integer, e.g. an empty segment ("2001:db8::/32::0"), non-numeric text ("/32x:0"), or a segment with whitespace or signs.

Common situations: Hand-edited cluster spec or Terraform output where the cidrsubnet-style notation was malformed; copy/paste errors dropping a digit; templating that produced an empty middle segment; confusing the notation with standard CIDR syntax and writing a netmask instead of new-bits.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/2455ba3cbc234161. Report an issue: GitHub.