hashicorp/terraform · error

invalid CIDR expression: %s

Error message

invalid CIDR expression: %s

What it means

Returned by the cidrhost built-in (CidrHostFunc, internal/lang/funcs/cidr.go:40) when ipaddr.ParseCIDR(args[0].AsString()) fails for the prefix argument. ParseCIDR requires true CIDR notation (address/prefixlen, e.g. 10.0.0.0/16); a bare IP, a host with a host portion set, or a malformed string all fail and the error is surfaced verbatim as the second %s.

Source

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

		{
			Name: "prefix",
			Type: cty.String,
		},
		{
			Name: "hostnum",
			Type: cty.Number,
		},
	},
	Type:         function.StaticReturnType(cty.String),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		var hostNum *big.Int
		if err := gocty.FromCtyValue(args[1], &hostNum); err != nil {
			return cty.UnknownVal(cty.String), err
		}
		_, network, err := ipaddr.ParseCIDR(args[0].AsString())
		if err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
		}

		ip, err := cidr.HostBig(network, hostNum)
		if err != nil {
			return cty.UnknownVal(cty.String), err
		}

		return cty.StringVal(ip.String()), nil
	},
})

// 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,

View on GitHub (pinned to c9def3e214)

Solutions

  1. Provide the prefix with an explicit mask: cidrhost("10.0.0.0/16", 5).
  2. If the prefix is computed, ensure it always carries a /mask before being passed to cidrhost.
  3. Guard null/unknown: only call cidrhost when the prefix var is known and non-empty.
  4. Use cidrsubnet/cidrsubnets to derive valid network prefixes from a base CIDR.

Example fix

# before (HCL)
output "ip" {
  value = cidrhost(var.base_cidr, 5)
}
# var.base_cidr = "10.0.0.0" (no mask) -> invalid CIDR expression

# after
output "ip" {
  value = cidrhost("10.0.0.0/16", 5)
}
# or guard:
output "ip" {
  value = var.base_cidr != "" ? cidrhost(var.base_cidr, 5) : null
}
Defensive patterns

Strategy: validation

Validate before calling

# (HCL) guard before calling cidrhost
output "ip" {
  value = var.cidr != "" && can(regex("/.+", var.cidr)) ? cidrhost(var.cidr, 5) : null
}

Type guard

// (Go) true if the string is parseable as CIDR
func isValidCIDR(s string) bool {
    _, _, err := net.ParseCIDR(s)
    return err == nil
}

Try / catch

# (HCL) use try to fall back gracefully
value = try(cidrhost(var.cidr, 5), null)

Prevention

When it happens

Trigger: Calling cidrhost(prefix, hostnum) where prefix is not valid CIDR: missing /mask (e.g. "10.0.0.0"), host bits set in what should be a network (some parsers reject), invalid octets, or a non-IP string. The function then returns cty.UnknownVal(String) plus this error.

Common situations: Forgetting the /mask in cidrhost("10.0.0.0", 5), passing a variable that is null/empty at evaluate time, a computed CIDR that resolves to a bare IP, IPv4/IPv6 formatting mistakes, or copy-paste of a gateway IP instead of a network prefix.

Related errors


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