hashicorp/terraform · error

IPv6 addresses cannot have a netmask

Error message

IPv6 addresses cannot have a netmask: %s

What it means

cidrnetmask() error specific to IPv6: cidrnetmask is defined only for IPv4 (which uses dotted-decimal masks). When the parsed CIDR is IPv6 (network.IP.To4() == nil), the function refuses to compute a netmask because IPv6 uses CIDR length notation only and has no equivalent dotted mask.

Solutions

  1. For IPv6 use the prefix length directly (e.g. split on '/' to get /32) instead of cidrnetmask.
  2. Branch on family: check the address contains ':' before calling cidrnetmask.
  3. Constrain the variable validation to IPv4 CIDRs if cidrnetmask is required.

Example fix

// before
locals { mask = cidrnetmask(var.cidr) } # fails for IPv6

// after
locals { mask = var.cidr == "" ? null : (can(regex(":", var.cidr)) ? split("/", var.cidr)[1] : cidrnetmask(var.cidr)) }
Defensive patterns

Strategy: validation

Validate before calling

// Branch on address family before calling cidrnetmask.
locals {
  is_v6 = can(regex(":", var.cidr))
  mask  = local.is_v6 ? split("/", var.cidr)[1] : cidrnetmask(var.cidr)
}

Prevention

When it happens

Trigger: Calling cidrnetmask("2001:db8::/32") or any IPv6 CIDR; To4() returns nil and the function returns this error including the offending prefix.

Common situations: Variable that can be either IPv4 or IPv6 family (dual-stack configs), a recently migrated network from v4 to v6, or a module that hard-codes cidrnetmask over a generic cidr variable.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/c29ae70e1ba84f48. Report an issue: GitHub.

Appendix: source

Thrown at internal/lang/funcs/cidr.go:70

// CidrNetmaskFunc contructs a function that converts an IPv4 address prefix given
// in CIDR notation into a subnet mask address.
var CidrNetmaskFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "prefix",
			Type: cty.String,
		},
	},
	Type:         function.StaticReturnType(cty.String),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		_, network, err := ipaddr.ParseCIDR(args[0].AsString())
		if err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
		}

		if network.IP.To4() == nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("IPv6 addresses cannot have a netmask: %s", args[0].AsString())
		}

		return cty.StringVal(ipaddr.IP(network.Mask).String()), nil
	},
})

// CidrSubnetFunc contructs a function that calculates a subnet address within
// a given IP network address prefix.
var CidrSubnetFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "prefix",
			Type: cty.String,
		},
		{
			Name: "newbits",
			Type: cty.Number,
		},

View on GitHub (pinned to d32a084675)