k3s-io/k3s · error

invalid endpoint URL %s for %s: %v

Error message

invalid endpoint URL %s for %s: %v

What it means

defaultHostConfig builds containerd's host configuration for each registry host from registries.yaml and first normalizes the endpoint via normalizeEndpointAddress(host, mirrorAddr). If that returns a parse error, it is wrapped as 'invalid endpoint URL <host> for <host>: <cause>' — both placeholders are the registry host key, and the wrapped cause says exactly what failed to parse.

Source

Thrown at pkg/agent/containerd/config.go:275

	// This is the reverse of the DefaultHost normalization
	if endpointURL.Host == "registry-1.docker.io" {
		registry = "docker.io"
	}

	switch endpointURL.Path {
	case "", "/", "/v2":
		// If the path is empty, /, or /v2, use the default path.
		endpointURL.Path = "/v2"
		return registry, endpointURL, false, nil
	}

	return registry, endpointURL, true, nil
}

func defaultHostConfig(host, mirrorAddr string, config registries.RegistryConfig) (*templates.HostConfig, error) {
	_, url, _, err := normalizeEndpointAddress(host, mirrorAddr)
	if err != nil {
		return nil, fmt.Errorf("invalid endpoint URL %s for %s: %v", host, host, err)
	}
	if host == "*" {
		url = nil
	}
	return &templates.HostConfig{
		Program: version.Program,
		Default: &templates.RegistryEndpoint{
			URL:    url,
			Config: config,
		},
	}, nil
}

func configForHost(configs map[string]registries.RegistryConfig, host string) registries.RegistryConfig {
	// check for config under modified hostname. If the hostname is unmodified, or there is no config for
	// the modified hostname, return the config for the default hostname.
	if h, _ := docker.DefaultHost(host); h != host {
		if c, ok := configs[h]; ok {

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Use fully-qualified endpoints with a scheme: https://mirror.example.com:5000
  2. Quote IPv6 literals correctly: "http://[2001:db8::1]:5000"
  3. Lint the registries.yaml before deploying and restart the agent/server after fixing

Example fix

# before (registries.yaml)
mirrors:
  docker.io:
    endpoint:
      - "mirror.example.com:5000"

# after
mirrors:
  docker.io:
    endpoint:
      - "https://mirror.example.com:5000"
Defensive patterns

Strategy: validation

Validate before calling

for _, ep := range endpoints {
    if _, err := url.Parse(strings.TrimSpace(ep)); err != nil {
        return fmt.Errorf("registries.yaml endpoint %q is not a valid URL: %w", ep, err)
    }
}

Prevention

When it happens

Trigger: A registries.yaml entry whose endpoint or mirror address cannot be parsed as a URL: malformed scheme ('http s://x'), stray characters, a broken IPv6 literal ('http://[::1'), or an empty endpoint string.

Common situations: Hand-edited /etc/rancher/k3s/registries.yaml; IPv6 mirror addresses missing brackets; URLs pasted with spaces or smart quotes; YAML values mangled by templating.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/3ab53b624b84222d. Report an issue: GitHub.