caddyserver/caddy · error
server %s: listener address repeated: %s (already claimed by
Error message
server %s: listener address repeated: %s (already claimed by server '%s')
What it means
App.Validate builds a set of all listener addresses (expanding port ranges) across servers and rejects duplicates. Each concrete network/host/port must be claimed by exactly one server, or config validation fails, naming both the offending and the earlier server.
Source
Thrown at modules/caddyhttp/app.go:431
}
// Validate ensures the app's configuration is valid.
func (app *App) Validate() error {
lnAddrs := make(map[string]string)
for srvName, srv := range app.Servers {
// each server must use distinct listener addresses
for _, addr := range srv.Listen {
listenAddr, err := caddy.ParseNetworkAddress(addr)
if err != nil {
return fmt.Errorf("invalid listener address '%s': %v", addr, err)
}
// check that every address in the port range is unique to this server;
// we do not use <= here because PortRangeSize() adds 1 to EndPort for us
for i := uint(0); i < listenAddr.PortRangeSize(); i++ {
addr := caddy.JoinNetworkAddress(listenAddr.Network, listenAddr.Host, strconv.FormatUint(uint64(listenAddr.StartPort+i), 10))
if sn, ok := lnAddrs[addr]; ok {
return fmt.Errorf("server %s: listener address repeated: %s (already claimed by server '%s')", srvName, addr, sn)
}
lnAddrs[addr] = srvName
}
}
// logger names must not have ports
if srv.Logs != nil {
for host := range srv.Logs.LoggerNames {
if _, _, err := net.SplitHostPort(host); err == nil {
return fmt.Errorf("server %s: logger name must not have a port: %s", srvName, host)
}
}
}
}
return nil
}
func removeTLSALPN(srv *Server, target string) {View on GitHub (pinned to 50e54ee279)
Solutions
- Give each server distinct addresses/ports (or non-overlapping ranges)
- If both should share an address, merge them into one server and route by host matcher
- Check for overlapping port ranges when using ranges
Example fix
// before srv1.listen=[":443"], srv2.listen=[":443"] // after srv1.listen=[":443"] with host matchers for both sites
Defensive patterns
Strategy: validation
Validate before calling
seen := map[string]string{}
for sn, s := range srvCfg.Servers {
for _, a := range s.Listen {
na, _ := caddy.ParseNetworkAddress(a)
for i := uint(0); i < na.PortRangeSize(); i++ {
key := caddy.JoinNetworkAddress(na.Network, na.Host, strconv.Itoa(int(na.StartPort+i)))
if prev, dup := seen[key]; dup {
return fmt.Errorf("%s duplicated by %s and %s", key, prev, sn)
}
seen[key] = sn
}
}
} Prevention
- One server per address; multiplex sites with host matchers
- When using port ranges, double-check range overlaps across servers
- Run `caddy validate` after every server split/merge refactor
When it happens
Trigger: Two servers both listening on :443, overlapping port ranges (server A: 8080-8090, server B: 8085), or the same unix socket path in two servers. Since map iteration order varies, either server may be named first.
Common situations: Adding a second site block that gets its own server object with the same address; splitting HTTP/1-only and HTTP/3 servers but keeping identical listen addresses; port-range configs that accidentally overlap.
Related errors
- must be exactly one listener address; cannot listen on: %s
- invalid listener address '%s': %v
- parsing listener address: %v
- 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/df93dcbcf95036bf.
Report an issue: GitHub.