joewalnes/websocketd · error
cannot derive redirect address from %q: %w
Error message
cannot derive redirect address from %q: %w
What it means
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.
Source
Thrown at main.go:163
conn.Close()
return fmt.Errorf("socket %s is already in use by a running server", path)
}
if err := os.Remove(path); err != nil {
return fmt.Errorf("failed to remove stale socket %s: %w", path, err)
}
}
return serve("unix", path, config, log)
}
// redirectAddress returns addr with its port replaced by redirPort. IPv6
// literals must be split with net.SplitHostPort (which understands brackets);
// splitting on the first colon lands inside "[::1]:port" and produced a
// malformed listener address that failed to bind — and, being a listener
// error, killed every other listener too.
func redirectAddress(addr string, redirPort int) (string, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return "", fmt.Errorf("cannot derive redirect address from %q: %w", addr, err)
}
return net.JoinHostPort(host, strconv.Itoa(redirPort)), nil
}
// redirectLocation builds the redirect server's Location header: the host
// the client itself sent, switched to the canonical scheme and the main
// server's port. Not an open redirect: the target host is the client's own
// Host header, only the port is rewritten.
func redirectLocation(clientHost, listenAddr string, ssl bool) string {
scheme := "http"
if ssl {
scheme = "https"
}
host, _, err := net.SplitHostPort(clientHost)
if err != nil {
host = clientHost // no port in Host header — use it verbatim
}
_, port, err := net.SplitHostPort(listenAddr)View on GitHub (pinned to 7a8683dc7f)
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.
Example fix
// before --addr=::1 --port=8080 // after --addr=[::1] --port=8080
Defensive patterns
Strategy: validation
Validate before calling
func validListenAddr(addr string) error {
if strings.Contains(addr, "://") { return fmt.Errorf("strip the scheme from %q", addr) }
_, _, err := net.SplitHostPort(addr)
return err
} Try / catch
if err := start(); err != nil && strings.Contains(err.Error(), "cannot derive redirect address") {
log.Fatalf("bad --addr: use host:port and bracket IPv6 (e.g. [::1]:8080): %v", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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`).
Related errors
- ambiguous: provided COMMAND and --dir argument, please only
- did you mean to specify COMMAND instead of --dir '%s'?
- origin list matches were not found
- failed to chmod unix socket %s to %o: %w
- failed to read CA file %s: %w
AI-assisted analysis of joewalnes/websocketd@7a8683dc7f (2026-09-03).
Data as JSON: /api/errors/4e84192ca0c98887.
Report an issue: GitHub.