k3s-io/k3s · error

failed to read http config %s: %w

Error message

failed to read http config %s: %w

What it means

When --config points at an http:// or https:// URL, readConfigFileData fetches it with a plain http.Get. This error wraps any transport-level failure: DNS resolution, connection refused, TLS handshake error, or timeout. Note the code does not check the HTTP status code, so a 404 page is read as config content and fails later at YAML parsing.

Source

Thrown at pkg/configfilearg/parser.go:343

		if str == "" {
			return nil
		}
		return []any{str}
	}
}

// readConfigFileData returns the contents of a local or remote file
func readConfigFileData(file string) ([]byte, error) {
	u, err := url.Parse(file)
	if err != nil {
		return nil, fmt.Errorf("failed to parse config location %s: %w", file, err)
	}

	switch u.Scheme {
	case "http", "https":
		resp, err := http.Get(file)
		if err != nil {
			return nil, fmt.Errorf("failed to read http config %s: %w", file, err)
		}
		defer resp.Body.Close()
		return io.ReadAll(resp.Body)
	default:
		return os.ReadFile(file)
	}
}

View on GitHub (pinned to 6ba341e396)

Solutions

  1. From the same node, verify the URL: `curl -fsSL https://host/k3s.yaml` and fix whatever it reports (DNS, firewall, TLS).
  2. For self-signed certs, install the CA into the host trust store; this code path has no skip-verify option.
  3. If the endpoint is unreliable, download the file locally and pass a local path: `curl -o /etc/rancher/k3s/config.yaml ... && k3s server --config /etc/rancher/k3s/config.yaml`.

Example fix

# before
ExecStart=/usr/local/bin/k3s server --config https://cfg.internal:8443/k3s.yaml

# after (bootstrap copies it locally, immune to config-server outages)
ExecStartPre=/usr/bin/curl -fsSL https://cfg.internal:8443/k3s.yaml -o /etc/rancher/k3s/config.yaml
ExecStart=/usr/local/bin/k3s server --config /etc/rancher/k3s/config.yaml
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: URL must be reachable AND return 2xx (k3s itself ignores status codes):
resp, err := http.Get(cfgURL)
if err != nil || resp.StatusCode < 200 || resp.StatusCode > 299 {
    log.Fatalf("config URL precheck failed: err=%v status=%v", err, resp.StatusCode)
}
resp.Body.Close()

Try / catch

// When fetching the config yourself, retry transient errors, fail fast on permanent ones:
var body []byte
err := retry(5, time.Second*2, func() error {
    resp, err := http.Get(cfgURL)
    if err != nil {
        var dnsErr *net.DNSError
        if errors.As(err, &dnsErr) { return err } // retryable
        return err
    }
    defer resp.Body.Close()
    if resp.StatusCode != 200 { return fmt.Errorf("status %d", resp.StatusCode) }
    body, err = io.ReadAll(resp.Body)
    return err
})

Prevention

When it happens

Trigger: `k3s server --config https://host/k3s.yaml` where the host is unreachable, DNS fails, the TLS certificate is untrusted (no insecure-skip-verify here), or a proxy/firewall blocks the request (pkg/configfilearg/parser.go:341-344).

Common situations: Config server down in air-gapped or PXE-booted environments; self-signed certificate not in the host trust store; typo in the URL; egress firewall blocking the port.

Related errors


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