ahmetb/kubectx · error

failed to parse server URL %q: %w

Error message

failed to parse server URL %q: %w

What it means

After loading the rest config, Start parses restCfg.Host (the API server address taken from the kubeconfig's cluster server field) with url.Parse. This error wraps a url.Parse failure and quotes the offending host string. It indicates the server address stored in the kubeconfig is not a parseable URL.

Source

Thrown at internal/proxy/readonly.go:73

	ContextName    string
}

// Start creates and starts a readonly reverse proxy on a random localhost port.
// The proxy loads TLS/auth config from the kubeconfig and forwards only
// GET, HEAD, and OPTIONS requests (without protocol upgrades) to the real API server.
func Start(cfg Config) (*ReadonlyProxy, error) {
	loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: cfg.KubeconfigPath}
	overrides := &clientcmd.ConfigOverrides{CurrentContext: cfg.ContextName}
	clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)

	restCfg, err := clientConfig.ClientConfig()
	if err != nil {
		return nil, fmt.Errorf("failed to load kubeconfig: %w", err)
	}

	targetURL, err := url.Parse(restCfg.Host)
	if err != nil {
		return nil, fmt.Errorf("failed to parse server URL %q: %w", restCfg.Host, err)
	}

	transport, err := rest.TransportFor(restCfg)
	if err != nil {
		return nil, fmt.Errorf("failed to create transport: %w", err)
	}

	handler := NewHandler(targetURL, transport)

	listener, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return nil, fmt.Errorf("failed to listen: %w", err)
	}

	srv := &http.Server{Handler: handler}
	go srv.Serve(listener)

	debugLog.Printf("started on %s, proxying to %s", listener.Addr(), targetURL)

View on GitHub (pinned to 12ad6fb22e)

Solutions

  1. Inspect the quoted host in the error message and fix the cluster's server field: kubectl config set-cluster <name> --server=https://<host>:6443
  2. Ensure the server URL includes a scheme (https://) and a valid host; wrap bare IPv6 addresses in brackets
  3. Re-generate the kubeconfig from the cluster (kubeadm/minikube/kind) if it was hand-edited badly
  4. Pre-validate in code: parse the server field yourself before Start to produce a clearer failure

Example fix

// before
// kubeconfig cluster:
//   server: 10.0.0 5:6443
// after
//   server: https://10.0.0.5:6443
Defensive patterns

Strategy: validation

Validate before calling

// Go
// Pre-validate the cluster server URL before Start
raw, _ := os.ReadFile(cfg.KubeconfigPath)
parsed, err := clientcmd.Load(raw)
if err != nil { return err }
ctxName := cfg.ContextName
if ctxName == "" { ctxName = parsed.CurrentContext }
cl := parsed.Contexts[ctxName].Cluster
srv := parsed.Clusters[cl].Server
if u, err := url.Parse(srv); err != nil || u.Host == "" {
    return fmt.Errorf("cluster %q has invalid server %q", cl, srv)
}

Try / catch

if err := start(); err != nil {
    if strings.Contains(err.Error(), "failed to parse server URL") {
        var uerr *url.Error
        if errors.As(err, &uerr) {
            return fmt.Errorf("fix cluster server field (%v): %w", uerr.URL, err)
        }
    }
    return err
}

Prevention

When it happens

Trigger: Calling Start when the selected cluster's server field contains a malformed URL — e.g. missing scheme with invalid characters, whitespace, control characters, or other strings that violate RFC 3986 parsing rules.

Common situations: Hand-edited kubeconfig with a typo'd server value (stray space, unescaped characters); a cluster entry generated by tooling with an empty or placeholder server; shell interpolation mangling the value (unexpanded variable, truncated IPv6 address without brackets).

Understand the failure class

Related errors


AI-assisted analysis of ahmetb/kubectx@12ad6fb22e (2026-09-02). Data as JSON: /api/errors/102249c0914d7f2e. Report an issue: GitHub.