k3s-io/k3s · warning

etcd disabled

Error message

etcd disabled

What it means

The Bootstrap handler in pkg/server/handlers/handlers.go serves /v1-k3s/bootstrap. When control.Runtime.HTTPBootstrap is nil - true when the datastore is not embedded etcd (SQLite default or external datastore) - the fallback handler logs 'Received HTTP bootstrap request from ..., but embedded etcd is not enabled.' and returns HTTP 400 'etcd disabled'. Only embedded-etcd servers implement HTTP bootstrap.

Source

Thrown at pkg/server/handlers/handlers.go:208

		if control.Runtime.Core == nil {
			util.SendError(util.ErrCoreNotReady, resp, req, http.StatusServiceUnavailable)
			return
		}
		data := []byte("ok")
		resp.WriteHeader(http.StatusOK)
		resp.Header().Set("Content-Type", "text/plain")
		resp.Header().Set("Content-Length", strconv.Itoa(len(data)))
		resp.Write(data)
	})
}

func Bootstrap(control *config.Control) http.Handler {
	if control.Runtime.HTTPBootstrap != nil {
		return control.Runtime.HTTPBootstrap
	}
	return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
		logrus.Warnf("Received HTTP bootstrap request from %s, but embedded etcd is not enabled.", req.RemoteAddr)
		util.SendError(errors.New("etcd disabled"), resp, req, http.StatusBadRequest)
	})
}

func Static(urlPrefix, staticDir string) http.Handler {
	return http.StripPrefix(urlPrefix, http.FileServer(http.Dir(staticDir)))
}

// csrSigner wraps a CSR with a Public() method and dummy Sign() method to satisfy the
// crypto.Signer interface required by dynamiclistener's cert helpers.
type csrSigner struct {
	csr *x509.CertificateRequest
}

func (c *csrSigner) Public() crypto.PublicKey {
	return c.csr.PublicKey
}

func (c csrSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, error) {

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Point joining nodes' --server at an embedded-etcd server (in an etcd HA cluster, any etcd member).
  2. Verify the target server's datastore: 'k3s kubectl get -o json leve... ' or simpler, check that /v1-k3s/bootstrap on an etcd member answers 200.
  3. If you did not intend a bootstrap call, exclude /v1-k3s/bootstrap from probes/scanners hitting the supervisor port.

Example fix

# before: joining against a SQLite/external-DB server -> 400 etcd disabled
k3s server --server https://sqlite-node:6443 --token ...

# after: join an embedded-etcd member
k3s server --server https://etcd-node:6443 --token ...
Defensive patterns

Strategy: validation

Validate before calling

# Before pointing a join at a server, confirm it runs embedded etcd
systemctl show k3s -p ExecStart | grep -q 'etcd' || echo 'target may reject bootstrap'

Try / catch

if resp.StatusCode == http.StatusBadRequest && strings.Contains(body, "etcd disabled") {
    // redirect the join to an embedded-etcd server; this node will never serve bootstrap
}

Prevention

When it happens

Trigger: A node (agent or joining server) sends a bootstrap request to a k3s server whose datastore is SQLite or an external SQL database, i.e. started without embedded etcd. Also seen when a client manually hits /v1-k3s/bootstrap on such a server.

Common situations: Mixed HA setup where a join URL points at a non-etcd server; nodes configured with a --server URL to a SQLite-backed node; curl/health-check traffic probing the endpoint.

Related errors


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