caddyserver/caddy · error

invalid admin address %s: %v

Error message

invalid admin address %s: %v

What it means

Thrown by AdminAPIRequest when the admin endpoint address passed to the CLI cannot be parsed by caddy.ParseNetworkAddress, or when it expands to more than one port. The address must be a single, well-formed network address such as 'localhost:2019', '127.0.0.1:2019', or 'unix//run/caddy/admin.sock'. Any parse error is wrapped into this message along with the offending address.

Source

Thrown at cmd/commandfuncs.go:777

	for _, envfile := range envfileFlag {
		if err := loadEnvFromFile(envfile); err != nil {
			return fmt.Errorf("loading additional environment variables: %v", err)
		}
	}

	return nil
}

// AdminAPIRequest makes an API request according to the CLI flags given,
// with the given HTTP method and request URI. If body is non-nil, it will
// be assumed to be Content-Type application/json. The caller should close
// the response body. Should only be used by Caddy CLI commands which
// need to interact with a running instance of Caddy via the admin API.
func AdminAPIRequest(adminAddr, method, uri string, headers http.Header, body io.Reader) (*http.Response, error) {
	parsedAddr, err := caddy.ParseNetworkAddress(adminAddr)
	if err != nil || parsedAddr.PortRangeSize() > 1 {
		return nil, fmt.Errorf("invalid admin address %s: %v", adminAddr, err)
	}
	origin := "http://" + parsedAddr.JoinHostPort(0)
	if parsedAddr.IsUnixNetwork() {
		origin = "http://127.0.0.1" // bogus host is a hack so that http.NewRequest() is happy

		// the unix address at this point might still contain the optional
		// unix socket permissions, which are part of the address/host.
		// those need to be removed first, as they aren't part of the
		// resulting unix file path
		addr, _, err := internal.SplitUnixSocketPermissionsBits(parsedAddr.Host)
		if err != nil {
			return nil, err
		}
		parsedAddr.Host = addr
	} else if parsedAddr.IsFdNetwork() {
		origin = "http://127.0.0.1"
	}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Pass a plain host:port without a scheme, e.g. --address localhost:2019
  2. Remove any port range; the admin endpoint must be exactly one port
  3. For unix sockets use the unix/ prefix, e.g. unix//run/caddy/admin.sock
  4. If the address comes from the config, fix the admin.listen value and reload

Example fix

# before
caddy reload --address http://localhost:2019

# after
caddy reload --address localhost:2019
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking commands that hit the admin API, confirm the address parses
// to exactly one port:
addr, err := caddy.ParseNetworkAddress(adminAddr)
if err != nil || addr.PortRangeSize() > 1 {
    return fmt.Errorf("admin address %q must be a single host:port (no scheme, no port range)", adminAddr)
}

Prevention

When it happens

Trigger: Calling any CLI command that talks to the admin API (reload, stop, list-modules, adapt via API, etc.) with --address set to a malformed value: empty host with bad port ('localhost:'), a port range like 'localhost:2019-2020', an unknown network prefix, or a stray scheme like 'http://localhost:2019'.

Common situations: Users prefixing http:// to the admin address (it is not a URL), copying a port range from a site address into the admin listen, or setting the admin listen in the config to a multi-port range and then running 'caddy reload --address ...'.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/774008be2cfb41be. Report an issue: GitHub.