kopia/kopia · error · ErrDisallowedPublicBind

: hostname is not localhost; pass -- only in isolated lab…

Error message

%w: hostname %q is not localhost; pass --%s only in isolated lab environments (extremely dangerous)

What it means

The final branch of ValidateListenAddressFlag: the host is neither empty, nor "localhost", nor a parseable IP, i.e. a DNS hostname other than localhost. For an unauthenticated server the validator cannot prove it is loopback-only, so it refuses with ErrDisallowedPublicBind.

Solutions

  1. Replace the hostname with an explicit loopback address (127.0.0.1:51515).
  2. Use the literal hostname "localhost" which is explicitly accepted.
  3. Use a unix socket address.
  4. Configure a server password, or pass --allow-extremely-dangerous-unauthenticated-server-on-the-network in a lab environment.

Example fix

// before
--address kopia.internal:51515
// after
--address localhost:51515
Defensive patterns

Strategy: validation

Validate before calling

host, _, _ := ParseListenHost(addr)
if host != "localhost" && net.ParseIP(host) == nil {
    return errors.New("use an explicit loopback IP instead of a hostname")
}

Try / catch

if err := ValidateListenAddressFlag(addr); err != nil {
    return fmt.Errorf("insecure server refused to start: %w", err)
}

Prevention

When it happens

Trigger: --address with a hostname such as "myhost.local:51515", "kopia.example.com:51515", or any non-localhost name while running insecure and passwordless.

Common situations: Using a machine's DNS name or /etc/hosts alias to listen; container hostnames; copy-pasted remote server URLs as listen addresses.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/a275ba2f07b9f1e1. Report an issue: GitHub.

Appendix: source

Thrown at internal/insecureserverbind/insecureserverbind.go:105

	if host == "" {
		return fmt.Errorf("%w: missing host in listen address %q binds all interfaces; use loopback, a unix socket, or pass --%s (extremely dangerous)",
			ErrDisallowedPublicBind, address, AllowDangerousUnauthenticatedNetworkFlag)
	}

	if strings.EqualFold(host, "localhost") {
		return nil
	}

	if ip := net.ParseIP(host); ip != nil {
		if ip.IsLoopback() {
			return nil
		}

		return fmt.Errorf("%w: %q is not a loopback address; pass --%s only in isolated lab environments (extremely dangerous)",
			ErrDisallowedPublicBind, host, AllowDangerousUnauthenticatedNetworkFlag)
	}

	return fmt.Errorf("%w: hostname %q is not localhost; pass --%s only in isolated lab environments (extremely dangerous)",
		ErrDisallowedPublicBind, host, AllowDangerousUnauthenticatedNetworkFlag)
}

// ValidateListenerAddr checks the bound listener address after Listen (covers socket activation).
func ValidateListenerAddr(addr net.Addr) error {
	switch a := addr.(type) {
	case *net.UnixAddr:
		return nil
	case *net.TCPAddr:
		if a.IP != nil && a.IP.IsLoopback() {
			return nil
		}

		return fmt.Errorf("%w: listener %v is not loopback; pass --%s only in isolated lab environments (extremely dangerous)",
			ErrDisallowedPublicBind, addr, AllowDangerousUnauthenticatedNetworkFlag)
	default:
		if addr.Network() == "unix" {
			return nil

View on GitHub (pinned to 82495e54b5)