{"record":{"id":"4e84192ca0c98887","repo":"joewalnes/websocketd","slug":"cannot-derive-redirect-address-from-q-w","errorCode":null,"errorMessage":"cannot derive redirect address from %q: %w","messagePattern":"cannot derive redirect address from %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"main.go","lineNumber":163,"sourceCode":"\t\t\tconn.Close()\n\t\t\treturn fmt.Errorf(\"socket %s is already in use by a running server\", path)\n\t\t}\n\t\tif err := os.Remove(path); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to remove stale socket %s: %w\", path, err)\n\t\t}\n\t}\n\treturn serve(\"unix\", path, config, log)\n}\n\n// redirectAddress returns addr with its port replaced by redirPort. IPv6\n// literals must be split with net.SplitHostPort (which understands brackets);\n// splitting on the first colon lands inside \"[::1]:port\" and produced a\n// malformed listener address that failed to bind — and, being a listener\n// error, killed every other listener too.\nfunc redirectAddress(addr string, redirPort int) (string, error) {\n\thost, _, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"cannot derive redirect address from %q: %w\", addr, err)\n\t}\n\treturn net.JoinHostPort(host, strconv.Itoa(redirPort)), nil\n}\n\n// redirectLocation builds the redirect server's Location header: the host\n// the client itself sent, switched to the canonical scheme and the main\n// server's port. Not an open redirect: the target host is the client's own\n// Host header, only the port is rewritten.\nfunc redirectLocation(clientHost, listenAddr string, ssl bool) string {\n\tscheme := \"http\"\n\tif ssl {\n\t\tscheme = \"https\"\n\t}\n\thost, _, err := net.SplitHostPort(clientHost)\n\tif err != nil {\n\t\thost = clientHost // no port in Host header — use it verbatim\n\t}\n\t_, port, err := net.SplitHostPort(listenAddr)","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/joewalnes/websocketd/blob/7a8683dc7f9778dc615945aaed2a8dc77290227b/main.go#L145-L181","documentation":"redirectAddress derives the HTTP→HTTPS redirect listener's address by replacing the port in the main address with net.SplitHostPort. If the configured address has no valid host:port shape, SplitHostPort fails and this wrapped error is returned, preventing a malformed bind that would have killed every listener.","triggerScenarios":"The --addr/port-derived listener address lacks a port or is otherwise malformed — e.g. passing an IPv6 literal without brackets like `--addr=::1`, a bare hostname with no colon, or a string with multiple unbracketed colons — while a redirect port is configured.","commonSituations":"Users writing `--addr=::1` instead of `[::1]:port`; empty or truncated address from a config template; copy-pasting an address that already includes a scheme (`http://host:8080`).","solutions":["Provide the address in host:port form, bracketing IPv6: --addr=[::1]:8080 not --addr=::1.","Strip any scheme from the address — websocketd wants only host:port.","Check the wrapped SplitHostPort error in the message: 'missing port' means add :port; 'too many colons' means bracket the IPv6 host.","If the address comes from env/config templating, log or echo the resolved value before starting."],"exampleFix":"// before\n--addr=::1 --port=8080\n// after\n--addr=[::1] --port=8080","handlingStrategy":"validation","validationCode":"func validListenAddr(addr string) error {\n    if strings.Contains(addr, \"://\") { return fmt.Errorf(\"strip the scheme from %q\", addr) }\n    _, _, err := net.SplitHostPort(addr)\n    return err\n}","typeGuard":null,"tryCatchPattern":"if err := start(); err != nil && strings.Contains(err.Error(), \"cannot derive redirect address\") {\n    log.Fatalf(\"bad --addr: use host:port and bracket IPv6 (e.g. [::1]:8080): %v\", err)\n}","preventionTips":["Always bracket IPv6 literals: --addr=[::1].","Never include a scheme (http://) in --addr.","Validate host:port format in config templates before deployment.","Log the fully resolved address at startup."],"tags":["address","ipv6","configuration","startup"],"backgroundTag":"invalid-listen-address","analyzedSha":"7a8683dc7f9778dc615945aaed2a8dc77290227b","analyzedAt":"2026-09-03T13:52:22.309Z","contentChangedAt":"2026-09-03T13:52:22.309Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}