JuliusBrussee/caveman · error
listen address %q is not loopback; standalone proxy has no i
Error message
listen address %q is not loopback; standalone proxy has no inbound authentication
What it means
validateListen parsed a host:port but the host is not loopback. The standalone caveman proxy forwards every configured provider credential with no inbound authentication, so binding to '', '0.0.0.0', '::', a LAN IP, or a resolvable non-loopback hostname is refused by design (config.go comment states this exposure directly).
Source
Thrown at proxy/internal/config/config.go:133
return Config{}, err
}
return cfg, nil
}
// validateListen keeps standalone's unauthenticated BYOK proxy local to one
// operator. Binding an empty, wildcard, or non-loopback host would expose every
// configured provider credential to the network with no inbound authentication.
func validateListen(listen string) error {
host, port, err := net.SplitHostPort(strings.TrimSpace(listen))
if err != nil || port == "" {
return fmt.Errorf("listen address %q must be loopback host:port", listen)
}
if strings.EqualFold(host, "localhost") {
return nil
}
ip := net.ParseIP(host)
if ip == nil || !ip.IsLoopback() {
return fmt.Errorf("listen address %q is not loopback; standalone proxy has no inbound authentication", listen)
}
return nil
}
func (c Config) withDefaults() Config {
if label := env.String("CAVEMAN_LABEL", ""); label != "" {
c.Label = label
}
if c.Label == "" {
c.Label = "local"
}
if mode := env.String("CAVEMAN_MODE", ""); mode != "" {
c.Mode = mode
}
if listen := env.String("CAVEMAN_LISTEN", ""); listen != "" {
c.Listen = listen
}
if sub := env.String("CAVEMAN_SUBSCRIPTION_COMPRESS", ""); sub != "" {View on GitHub (pinned to 27d5a3981a)
Solutions
- Bind to '127.0.0.1:8080' (or 'localhost:8080') and access it from the same machine
- For containers, use host networking (--network host) so loopback works, or run the proxy on the host itself
- To share the proxy safely, front it with an authenticated reverse proxy (e.g. nginx with TLS + auth) that proxies to the loopback listener
- Do not attempt to bypass this check; it protects unauthenticated provider credentials
Example fix
// before listen: ":8080" // empty host -> Error[1061] listen: "0.0.0.0:8080" // wildcard -> Error[1061] // after listen: "127.0.0.1:8080"
Defensive patterns
Strategy: validation
Validate before calling
func isLoopbackHost(host string) bool {
if strings.EqualFold(host, "localhost") {
return true
}
ip := net.ParseIP(host)
return ip != nil && ip.IsLoopback()
}
if !isLoopbackHost(host) {
// refuse to start; suggest 127.0.0.1 instead of widening the bind
} Prevention
- Never ship ':port' or '0.0.0.0' defaults — the proxy is unauthenticated BYOK
- In containers prefer host networking over wildcard binds
- Front an authenticated reverse proxy when off-box access is truly needed
When it happens
Trigger: listen = ':8080' (empty host), '0.0.0.0:8080', '192.168.1.10:8080', 'myhost.local:8080', or '[::]:8080'. 'localhost' and 127.0.0.0/8 and ::1 pass; everything else hits this error.
Common situations: Trying to run the proxy in a container and reach it from the host; wanting a teammate or another machine to share one proxy; DNS name that resolves to loopback is still rejected because only the literal string/IP is checked.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- listen address %q must be loopback host:port
- signature check failed for ${artifact} — partial download de
- invalid listen address %q: %w
- production requires an https:// CLICKHOUSE_URL (TLS only); C
- production KMS configuration: %w
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/63c951c61ce8dbdf.
Report an issue: GitHub.