k3s-io/k3s · error

failed to get etcd MemberList: etcd not started

Error message

failed to get etcd MemberList: etcd not started

What it means

The /db/info endpoint on a control-plane node answers GET requests from servers that are joining the etcd cluster. Before calling e.client.MemberList the handler checks that the embedded etcd client has been created; when e.client is nil (etcd never started, failed to start, or has not finished starting) it returns this error with HTTP 500. It is almost always a startup-ordering or etcd-failure condition, not a client bug.

Source

Thrown at pkg/etcd/etcd.go:753

	ir.Handle("/", e.infoHandler())

	sr := r.SubRouter("/db/snapshot")
	sr.Use(auth.HasRole(e.config, version.Program+":server"))
	sr.Handle("/", e.snapshotHandler())

	return r
}

// infoHandler returns etcd cluster information. This is used by new members when joining the cluster.
func (e *ETCD) infoHandler() http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		if req.Method != http.MethodGet {
			util.SendError(errors.New("method not allowed"), rw, req, http.StatusMethodNotAllowed)
			return
		}

		if e.client == nil {
			util.SendError(errors.New("failed to get etcd MemberList: etcd not started"), rw, req, http.StatusInternalServerError)
			return
		}

		ctx, cancel := context.WithTimeout(req.Context(), 2*time.Second)
		defer cancel()

		members, err := e.client.MemberList(ctx)
		if err != nil {
			util.SendError(errors.WithMessage(err, "failed to get etcd MemberList"), rw, req, http.StatusInternalServerError)
			return
		}

		rw.Header().Set("Content-Type", "application/json")
		json.NewEncoder(rw).Encode(&Members{
			Members: members.Members,
		})
	})
}

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Check the target node's logs (journalctl -u k3s or container logs) for etcd startup failures and fix the root cause (disk, certs, data-dir permissions).
  2. Retry the join request after waiting for etcd to become healthy: etcdctl endpoint status or wait for the /health endpoint of the server.
  3. Verify you are calling a control-plane (etcd) node, not an agent; agents do not serve /db/info.
  4. If etcd cannot start because of a corrupted data dir, restore with --cluster-reset (optionally --cluster-reset-restore-path) after backing up the db directory.

Example fix

# before: joining immediately while seed node boots
k3s server --server https://10.0.0.10:6443 --token ...
# after: wait for seed etcd readiness, then join
until curl -sk https://10.0.0.10:6443/ping; do sleep 2; done
k3s server --server https://10.0.0.10:6443 --token ...
Defensive patterns

Strategy: retry

Validate before calling

func etcdInfoReady(serverURL string, timeout time.Duration) bool {
	client := &http.Client{Timeout: timeout}
	resp, err := client.Get(serverURL + "/db/info")
	if err != nil {
		return false
	}
	defer resp.Body.Close()
	return resp.StatusCode == http.StatusOK
}

Try / catch

// in the joining node's retry loop
resp, err := clientAccessInfo.Get("/db/info")
if err != nil || resp.StatusCode == http.StatusInternalServerError {
    // server still starting etcd: back off and retry
    time.Sleep(5 * time.Second)
    continue
}

Prevention

When it happens

Trigger: A new server issues GET /db/info against a control-plane node whose ETCD.Start() has not yet completed (client still nil), or whose etcd exited/failed to initialize (bad certs, unreadable data-dir, panic). Any request to the endpoint before a successful etcd start produces the exact message.

Common situations: Joining a node to a cluster while the first control-plane node is still bootstrapping; etcd failing silently because of full disk or permission errors on /var/lib/rancher/k3s/server/db; hitting /db/info on a worker/agent node that never runs etcd; restart storms where the apiserver is up but etcd is not.

Related errors


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