{"record":{"id":"8913cb1cece92e61","repo":"k3s-io/k3s","slug":"failed-to-get-etcd-memberlist-etcd-not-started","errorCode":null,"errorMessage":"failed to get etcd MemberList: etcd not started","messagePattern":"failed to get etcd MemberList: etcd not started","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"pkg/etcd/etcd.go","lineNumber":753,"sourceCode":"\tir.Handle(\"/\", e.infoHandler())\n\n\tsr := r.SubRouter(\"/db/snapshot\")\n\tsr.Use(auth.HasRole(e.config, version.Program+\":server\"))\n\tsr.Handle(\"/\", e.snapshotHandler())\n\n\treturn r\n}\n\n// infoHandler returns etcd cluster information. This is used by new members when joining the cluster.\nfunc (e *ETCD) infoHandler() http.Handler {\n\treturn http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\tif req.Method != http.MethodGet {\n\t\t\tutil.SendError(errors.New(\"method not allowed\"), rw, req, http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\n\t\tif e.client == nil {\n\t\t\tutil.SendError(errors.New(\"failed to get etcd MemberList: etcd not started\"), rw, req, http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\n\t\tctx, cancel := context.WithTimeout(req.Context(), 2*time.Second)\n\t\tdefer cancel()\n\n\t\tmembers, err := e.client.MemberList(ctx)\n\t\tif err != nil {\n\t\t\tutil.SendError(errors.WithMessage(err, \"failed to get etcd MemberList\"), rw, req, http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\n\t\trw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tjson.NewEncoder(rw).Encode(&Members{\n\t\t\tMembers: members.Members,\n\t\t})\n\t})\n}","sourceCodeStart":735,"sourceCodeEnd":771,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/etcd/etcd.go#L735-L771","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Retry the join request after waiting for etcd to become healthy: etcdctl endpoint status or wait for the /health endpoint of the server.","Verify you are calling a control-plane (etcd) node, not an agent; agents do not serve /db/info.","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."],"exampleFix":"# before: joining immediately while seed node boots\nk3s server --server https://10.0.0.10:6443 --token ...\n# after: wait for seed etcd readiness, then join\nuntil curl -sk https://10.0.0.10:6443/ping; do sleep 2; done\nk3s server --server https://10.0.0.10:6443 --token ...","handlingStrategy":"retry","validationCode":"func etcdInfoReady(serverURL string, timeout time.Duration) bool {\n\tclient := &http.Client{Timeout: timeout}\n\tresp, err := client.Get(serverURL + \"/db/info\")\n\tif err != nil {\n\t\treturn false\n\t}\n\tdefer resp.Body.Close()\n\treturn resp.StatusCode == http.StatusOK\n}","typeGuard":null,"tryCatchPattern":"// in the joining node's retry loop\nresp, err := clientAccessInfo.Get(\"/db/info\")\nif err != nil || resp.StatusCode == http.StatusInternalServerError {\n    // server still starting etcd: back off and retry\n    time.Sleep(5 * time.Second)\n    continue\n}","preventionTips":["Gate cluster-join automation on a readiness probe of the seed control plane before requesting /db/info.","Monitor etcd startup logs so a nil client is caught as a node failure rather than a join failure.","Never call /db/info on agent nodes; only control-plane nodes run etcd."],"tags":["etcd","http","startup","cluster-join"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}