k3s-io/k3s · warning
etcd datastore disabled
Error message
etcd datastore disabled
What it means
When the server runs a non-etcd datastore (sqlite/postgres/mysql via --datastore-endpoint, or etcd disabled), the /db/ mux is wrapped by handlerNoEtcd: every request under /db/ answers 400 with 'etcd datastore disabled'. The etcd-specific database API simply does not exist for this datastore backend.
Source
Thrown at pkg/cluster/managed.go:151
// deleteNodePasswdSecret wipes out the node password secret after restoration
func (c *Cluster) deleteNodePasswdSecret(ctx context.Context) {
nodeName := os.Getenv("NODE_NAME")
if err := nodepassword.Delete(nodeName); err != nil {
if apierrors.IsNotFound(err) {
logrus.Debugf("Node password secret is not found for node %s", nodeName)
return
}
logrus.Warnf("failed to delete old node password secret: %v", err)
}
}
// handlerNoEtcd wraps a handler with an error message indicating that etcd is not deployed.
func handlerNoEtcd(handler http.Handler) http.Handler {
r := mux.NewRouter()
// Wildcard route for anything after /db/
r.HandleFunc("/db/", func(resp http.ResponseWriter, r *http.Request) {
util.SendError(errors.New("etcd datastore disabled"), resp, r, http.StatusBadRequest)
})
// Needs to come at the end, otherwise wildcard routes won't work
r.NotFoundHandler = handler
return r
}
View on GitHub (pinned to 6ba341e396)
Solutions
- Use datastore-appropriate tooling: SQL snapshots are handled by the local/k3s etcd-snapshot commands or database-native backups, not /db/snapshot.
- Join additional servers by pointing them at the same --datastore-endpoint, not via the etcd /db join path.
- Update scripts/agents to detect datastore type before calling /db endpoints and skip on non-etcd clusters.
Defensive patterns
Strategy: validation
Validate before calling
// Only call /db endpoints when the datastore is etcd:
func isEtcdDatastore(cfg Endpoint) bool {
return strings.HasPrefix(cfg.DatastoreEndpoint, "etcd") || cfg.DatastoreEndpoint == "" && !cfg.DisableEmbeddedEtcd
}
if isEtcdDatastore(cfg) { callDBInfo() } else { useSQLBackupTooling() } Try / catch
resp, err := http.Get(base + "/db/snapshot")
if err == nil && resp.StatusCode == http.StatusBadRequest {
body, _ := io.ReadAll(resp.Body)
if strings.Contains(string(body), "etcd datastore disabled") {
// switch to datastore-native backup path instead of /db API
}
} Prevention
- Make datastore type a first-class variable in your automation and branch on it before /db calls.
- Document which endpoints are etcd-only when adopting sqlite/PostgreSQL backends.
- Join extra servers via the shared --datastore-endpoint, never via the etcd /db flow.
When it happens
Trigger: Calling etcd-only endpoints (/db/info, /db/snapshot, /db/check, /db/connect) on a server started with a SQL datastore or with the managed etcd disabled; an agent or script hardcoding the etcd join flow against such a server.
Common situations: Migrating a cluster to sqlite/PostgreSQL and reusing old automation that hits /db routes; mixed servers where a joining node assumes embedded etcd; monitoring scraping etcd metrics endpoints.
Related errors
- no bootstrap data found in datastore - check server token va
- no bootstrap data found
- etcd disabled
- failed to migrate content from sqlite to etcd: %w
- invalid flag use; cannot use --disable-etcd with --datastore
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/424c73002f721381.
Report an issue: GitHub.