caddyserver/caddy · error
invalid IP address: '%s': %v
Error message
invalid IP address: '%s': %v
What it means
Companion to the CIDR branch in CIDRExpressionToPrefix (modules/caddyhttp/ip_range.go): an entry without '/' is parsed as a single IP with netip.ParseAddr; failure yields this error during module Provision. Because the function then builds a full-length prefix via PrefixFrom(addr, addr.BitLen()), the input must be a valid bare address.
Source
Thrown at modules/caddyhttp/ip_range.go:119
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)
)
// PrivateRangesCIDR returns a list of private CIDR range
// strings, which can be used as a configuration shortcut.
// Note: this function is used at least by mholt/caddy-l4.
func PrivateRangesCIDR() []string {
return internal.PrivateRangesCIDR()
}View on GitHub (pinned to 50e54ee279)
Solutions
- Use literal IPs only: ip_range 10.0.0.1.
- Strip empty lines/whitespace from generated lists.
- Avoid leading-zero octet notation; write 10.0.0.1, not 010.0.0.1.
- Validate each token with netip.ParseAddr in your config-generation pipeline.
Example fix
// before ip_range 010.0.0.1 // after ip_range 10.0.0.1
Defensive patterns
Strategy: validation
Validate before calling
import "net/netip"
func validSingleIPs(entries []string) bool {
for _, e := range entries {
if !strings.Contains(e, "/") {
if _, err := netip.ParseAddr(e); err != nil {
return false
}
}
}
return true
} Prevention
- Filter hostnames and empty strings out of generated IP lists.
- Write 10.0.0.1, never 010.0.0.1.
- Prefer subnets (/32, /128) over long single-IP lists.
When it happens
Trigger: A range entry that is a hostname (`ip_range 10.0.0.1 example.com`), a malformed address (`10.0.0`), or an empty token. Also any string Go's netip rejects, such as addresses with leading zeros (`010.0.0.1`).
Common situations: DNS names pasted into IP range lists; CSV/CMDB exports with blank or commented lines not filtered; environments where leading-zero octets were accepted by older parsers (inet_pton-style tools) but netip forbids them.
Related errors
- invalid IP address: '%s': %v
- parsing CIDR expression: '%s': %v
- parsing listener address: %v
- must be exactly one listener address; cannot listen on: %s
- indexing config: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/a9a54c02ff64be63.
Report an issue: GitHub.