caddyserver/caddy · error
parsing CIDR expression: '%s': %v
Error message
parsing CIDR expression: '%s': %v
What it means
CIDRExpressionToPrefix (modules/caddyhttp/ip_range.go) converts one entry of an IP range source (e.g. the static `source_ip_range` / `internal_ip_range`-style modules) into a netip.Prefix. When the entry contains '/', netip.ParsePrefix is used; failure produces this wrapped error during Provision. The offending expression is included verbatim.
Source
Thrown at modules/caddyhttp/ip_range.go:111
}
for d.NextArg() {
if d.Val() == "private_ranges" {
m.Ranges = append(m.Ranges, internal.PrivateRangesCIDR()...)
continue
}
m.Ranges = append(m.Ranges, d.Val())
}
return nil
}
// CIDRExpressionToPrefix takes a string which could be either a
// CIDR expression or a single IP address, and returns a netip.Prefix.
func CIDRExpressionToPrefix(expr string) (netip.Prefix, error) {
// Having a slash means it should be a CIDR expression
if strings.Contains(expr, "/") {
prefix, err := netip.ParsePrefix(expr)
if err != nil {
return netip.Prefix{}, fmt.Errorf("parsing CIDR expression: '%s': %v", expr, err)
}
return prefix, nil
}
// Otherwise it's likely a single IP address
parsed, err := netip.ParseAddr(expr)
if err != nil {
return netip.Prefix{}, fmt.Errorf("invalid IP address: '%s': %v", expr, err)
}
prefix := netip.PrefixFrom(parsed, parsed.BitLen())
return prefix, nil
}
// Interface guards
var (
_ caddy.Provisioner = (*StaticIPRange)(nil)
_ caddyfile.Unmarshaler = (*StaticIPRange)(nil)
_ IPRangeSource = (*StaticIPRange)(nil)View on GitHub (pinned to 50e54ee279)
Solutions
- Fix the entry to a valid prefix (IPv4 /0-/32, IPv6 /0-/128), e.g. 172.16.0.0/12.
- For a single address omit the slash entirely.
- Lint generated lists with netip.ParsePrefix before pushing config.
- Use `caddy validate --config <file>` in CI to catch provisioning errors pre-deploy.
Example fix
// before (Caddyfile) ip_range 172.16.0.0/12/12 // after ip_range 172.16.0.0/12
Defensive patterns
Strategy: validation
Validate before calling
import "net/netip"
func validRangeEntries(entries []string) bool {
for _, e := range entries {
if strings.Contains(e, "/") {
if _, err := netip.ParsePrefix(e); err != nil {
return false
}
}
}
return true
} Prevention
- Lint ip_range lists with netip.ParsePrefix in config pipelines.
- Keep one entry per token; no combined ranges like 10.0.0.0-10.0.0.9.
- Use caddy validate as a pre-deploy gate.
When it happens
Trigger: A range entry like `172.16.0.0/12/12`, mask out of family range (`2001:db8::/129`), or a value like `10.0.0.5/` after Caddyfile tokenizing. Anything with a slash but not a syntactically valid prefix.
Common situations: Caddyfile `ip_range` / range source blocks with typo'd masks; mixing up the argument order in directives; generating range lists from CMDB exports that contain stray '/' characters; version migrations where old configs tolerated looser parsing.
Related errors
- invalid IP address: '%s': %v
- parsing listener address: %v
- must be exactly one listener address; cannot listen on: %s
- indexing config: %v
- %s: %s field must be a string or number
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/7188052c6ba624e0.
Report an issue: GitHub.