kubernetes/kubernetes · info
external etcd detected, won't try to change any etcd state
Error message
external etcd detected, won't try to change any etcd state
What it means
Returned by performEtcdStaticPodUpgrade when cfg.Etcd.External != nil. It is a deliberate, non-fatal abort: kubeadm detects an externally-managed etcd and refuses to touch etcd state during a control-plane static-pod upgrade. The function returns fatal=false, signalling the caller that etcd upgrade was intentionally skipped rather than a hard failure.
Source
Thrown at cmd/kubeadm/app/phases/upgrade/staticpods.go:287
return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
}
}
// Wait for the static pod component to come up and register itself as a mirror pod
if err := waiter.WaitForPodsWithLabel("component=" + component); err != nil {
return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
}
fmt.Printf("[upgrade/staticpods] Component %q upgraded successfully!\n", component)
return nil
}
// performEtcdStaticPodUpgrade performs upgrade of etcd, it returns bool which indicates fatal error or not and the actual error.
func performEtcdStaticPodUpgrade(certsRenewMgr *renewal.Manager, client clientset.Interface, waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.InitConfiguration, recoverManifests map[string]string, oldEtcdClient, newEtcdClient etcdutil.ClusterInterrogator) (bool, error) {
// Add etcd static pod spec only if external etcd is not configured
if cfg.Etcd.External != nil {
return false, errors.New("external etcd detected, won't try to change any etcd state")
}
// Checking health state of etcd before proceeding with the upgrade
err := oldEtcdClient.CheckClusterHealth()
if err != nil {
return true, errors.Wrap(err, "etcd cluster is not healthy")
}
// Backing up etcd data store
backupEtcdDir := pathMgr.BackupEtcdDir()
runningEtcdDir := cfg.Etcd.Local.DataDir
output, err := filesutil.CopyDir(runningEtcdDir, backupEtcdDir)
if err != nil {
return true, errors.Wrapf(err, "failed to back up etcd data, output: %q", output)
}
// Get the desired etcd version. That's either the one specified by the user in cfg.Etcd.Local.ImageTag
// or the kubeadm preferred one for the desired Kubernetes versionView on GitHub (pinned to b882c60b40)
Solutions
- No action required for kubeadm: this is informational. Upgrade the external etcd cluster separately.
- If you expected stacked (local) etcd, verify your config does not set etcd.external; switch to local etcd config to let kubeadm manage etcd.
- Confirm the caller treats fatal=false as non-terminal (the upgrade of other static pods continues).
Defensive patterns
Strategy: validation
Validate before calling
if cfg.Etcd.External != nil {
// external etcd: skip etcd upgrade, log and continue
klog.Info("external etcd configured; skipping etcd static-pod upgrade")
return nil
}
return performEtcdStaticPodUpgrade(...) Try / catch
fatal, err := performEtcdStaticPodUpgrade(...)
if err != nil && !fatal && strings.Contains(err.Error(), "external etcd detected") {
klog.Infof("skipping etcd upgrade: %v", err)
err = nil
} Prevention
- Detect external etcd up front (cfg.Etcd.External != nil) and branch before calling etcd upgrade code.
- Treat fatal=false returns as intentional skips, not failures.
- Upgrade external etcd out-of-band; document the split responsibility.
When it happens
Trigger: Running 'kubeadm upgrade apply'/'upgrade node' on a cluster whose ClusterConfiguration.Etcd.External is populated (etcd endpoints/caCert/keyFile set), then kubeadm reaching the etcd static-pod upgrade phase via performEtcdStaticPodUpgrade.
Common situations: Clusters provisioned with external/managed etcd (e.g. etcd running on separate hosts or a managed service). This is expected and benign; the operator must upgrade external etcd themselves.
Related errors
- etcd static pod manifest cannot be generated for cluster usi
- empty manifest path
- invalid etcd pod manifest
- couldn't list all nodes in cluster
- ErrNoMemberIDForPeerURL
AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07).
Data as JSON: /api/errors/bbc69c343c460e32.
Report an issue: GitHub.