k3s-io/k3s · error

proxy URL must include scheme and host

Error message

proxy URL must include scheme and host

What it means

When --etcd-s3-proxy is set (and is not the literal 'none'), the value is parsed with url.Parse and must yield both a scheme and a host before it is installed as the transport proxy. url.Parse rarely errors on sloppy input, so this explicit check is what rejects ambiguous proxy strings.

Source

Thrown at pkg/etcd/s3/s3.go:204

		if err != nil {
			return nil, err
		}
		tr.TLSClientConfig = tlsConfig
	}

	// Set a fixed proxy URL, if requested by the user. This replaces the default,
	// which calls ProxyFromEnvironment to read proxy settings from the environment.
	if etcdS3.Proxy != "" {
		var u *url.URL
		var err error
		// proxy address of literal "none" disables all use of a proxy by S3
		if etcdS3.Proxy != "none" {
			u, err = url.Parse(etcdS3.Proxy)
			if err != nil {
				return nil, errors.WithMessage(err, "failed to parse etcd-s3-proxy value as URL")
			}
			if u.Scheme == "" || u.Host == "" {
				return nil, errors.New("proxy URL must include scheme and host")
			}
		}
		tr.Proxy = http.ProxyURL(u)
	}

	creds := credentials.NewChainCredentials([]credentials.Provider{
		&credentials.Static{
			Value: credentials.Value{
				AccessKeyID:     etcdS3.AccessKey,
				SecretAccessKey: etcdS3.SecretKey,
				SessionToken:    etcdS3.SessionToken,
				SignerType:      credentials.SignatureV4,
			},
		},
		&credentials.FileAWSCredentials{},
		&credentials.IAM{},
	})

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Include scheme and host: --etcd-s3-proxy=http://10.10.10.1:8080.
  2. To explicitly disable proxying use the literal --etcd-s3-proxy=none; to fall back to environment proxies, unset the flag.
  3. Validate the value with url.ParseRequestURI in CI/scripts before passing it to the server.

Example fix

# before
--etcd-s3-proxy=10.10.10.1:8080
# after
--etcd-s3-proxy=http://10.10.10.1:8080
Defensive patterns

Strategy: validation

Validate before calling

if etcdS3.Proxy != "" && etcdS3.Proxy != "none" {
    u, err := url.Parse(etcdS3.Proxy)
    if err != nil || u.Scheme == "" || u.Host == "" {
        return fmt.Errorf("proxy %q must look like http://host:port", etcdS3.Proxy)
    }
}

Type guard

func hasSchemeAndHost(s string) bool {
	u, err := url.Parse(s)
	return err == nil && u.Scheme != "" && u.Host != ""
}

Prevention

When it happens

Trigger: Setting --etcd-s3-proxy=10.10.10.1:8080 (missing scheme) or --etcd-s3-proxy=http:// (missing host); anything url.Parse accepts but that lacks scheme/host fails here.

Common situations: Reusing a proxy value from environment-style configs (which omit the scheme) in a flag that requires it; typos like 'http:/proxy:3128'; expecting the literal 'none' semantics with values like 'off' or 'disabled' (only 'none' is special).

Related errors


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