{"record":{"id":"54e7d0cb23796e0b","repo":"caddyserver/caddy","slug":"server-s-logger-name-must-not-have-a-port-s","errorCode":null,"errorMessage":"server %s: logger name must not have a port: %s","messagePattern":"server (.+?): logger name must not have a port: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/app.go","lineNumber":441,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"invalid listener address '%s': %v\", addr, err)\n\t\t\t}\n\t\t\t// check that every address in the port range is unique to this server;\n\t\t\t// we do not use <= here because PortRangeSize() adds 1 to EndPort for us\n\t\t\tfor i := uint(0); i < listenAddr.PortRangeSize(); i++ {\n\t\t\t\taddr := caddy.JoinNetworkAddress(listenAddr.Network, listenAddr.Host, strconv.FormatUint(uint64(listenAddr.StartPort+i), 10))\n\t\t\t\tif sn, ok := lnAddrs[addr]; ok {\n\t\t\t\t\treturn fmt.Errorf(\"server %s: listener address repeated: %s (already claimed by server '%s')\", srvName, addr, sn)\n\t\t\t\t}\n\t\t\t\tlnAddrs[addr] = srvName\n\t\t\t}\n\t\t}\n\n\t\t// logger names must not have ports\n\t\tif srv.Logs != nil {\n\t\t\tfor host := range srv.Logs.LoggerNames {\n\t\t\t\tif _, _, err := net.SplitHostPort(host); err == nil {\n\t\t\t\t\treturn fmt.Errorf(\"server %s: logger name must not have a port: %s\", srvName, host)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc removeTLSALPN(srv *Server, target string) {\n\tfor _, cp := range srv.TLSConnPolicies {\n\t\t// the TLSConfig was already provisioned, so... manually remove it\n\t\tfor i, np := range cp.TLSConfig.NextProtos {\n\t\t\tif np == target {\n\t\t\t\tcp.TLSConfig.NextProtos = append(cp.TLSConfig.NextProtos[:i], cp.TLSConfig.NextProtos[i+1:]...)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\t// remove it from the parent connection policy too, just to keep things tidy\n\t\tfor i, alpn := range cp.ALPN {","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/app.go#L423-L459","documentation":"In App.Validate, every key of servers.<name>.logs.logger_names must be a host name without a port. Because net.SplitHostPort succeeds on strings like \"example.com:8080\", such keys are rejected — log customization is keyed by host, not address.","triggerScenarios":"Writing a logger_names key that includes a port, e.g. {\"example.com:443\": \"logname\"}, typically when copying addresses from the listen array into the logs config.","commonSituations":"Adapting a Caddyfile where the site address includes a port and pasting it into the access_logs/logger_names JSON; multi-port setups where users assume logs are per-address.","solutions":["Strip the port: use just the host (\"example.com\") as the logger_names key","If you need per-port logging, use separate servers and set per-server access logging instead"],"exampleFix":"// before\n\"logs\":{\"logger_names\":{\"example.com:443\":\"web\"}}\n// after\n\"logs\":{\"logger_names\":{\"example.com\":\"web\"}}","handlingStrategy":"validation","validationCode":"for host := range srvCfg.Logs.LoggerNames {\n    if _, _, err := net.SplitHostPort(host); err == nil {\n        return fmt.Errorf(\"logger_names key %q must not contain a port\", host)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate logger_names keys from parsed hostnames, not from site address strings","Remember logs are keyed by host only; per-port behavior requires separate servers"],"tags":["caddy","logging","validation","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}