{"record":{"id":"1ec06db993f0ed5e","repo":"kubernetes/kops","slug":"backupstore-must-be-set-for-use-with-etcd-manager","errorCode":null,"errorMessage":"backupStore must be set for use with etcd-manager","messagePattern":"backupStore must be set for use with etcd-manager","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/components/etcdmanager/model.go","lineNumber":104,"sourceCode":"\n// EtcdManagerBuilder builds the manifest for the etcd-manager\ntype EtcdManagerBuilder struct {\n\t*model.KopsModelContext\n\tLifecycle    fi.Lifecycle\n\tAssetBuilder *assets.AssetBuilder\n}\n\nvar _ fi.CloudupModelBuilder = &EtcdManagerBuilder{}\n\n// Build creates the tasks\nfunc (b *EtcdManagerBuilder) Build(c *fi.CloudupModelBuilderContext) error {\n\tfor _, etcdCluster := range b.Cluster.Spec.EtcdClusters {\n\t\tbackupStore := \"\"\n\t\tif etcdCluster.Backups != nil {\n\t\t\tbackupStore = etcdCluster.Backups.BackupStore\n\t\t}\n\t\tif backupStore == \"\" {\n\t\t\treturn fmt.Errorf(\"backupStore must be set for use with etcd-manager\")\n\t\t}\n\n\t\tfor _, member := range etcdCluster.Members {\n\t\t\tinstanceGroupName := fi.ValueOf(member.InstanceGroup)\n\t\t\tmanifest, err := b.buildManifest(etcdCluster, instanceGroupName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tmanifestYAML, err := k8scodecs.ToVersionedYaml(manifest)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error marshaling manifest to yaml: %v\", err)\n\t\t\t}\n\n\t\t\tname := fmt.Sprintf(\"%s-%s\", etcdCluster.Name, instanceGroupName)\n\t\t\tc.AddTask(&fitasks.ManagedFile{\n\t\t\t\tContents:  fi.NewBytesResource(manifestYAML),\n\t\t\t\tLifecycle: b.Lifecycle,","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/components/etcdmanager/model.go#L86-L122","documentation":"During etcd-manager model building, kOps iterates over every etcdCluster in the cluster spec and requires a non-empty EtcdCluster.Backups.BackupStore. etcd-manager manages its own backup lifecycle, so kOps must know where backups are stored; an empty backupStore makes the resulting manifest ambiguous, so Build aborts with this error. It is a cluster spec validation error, not a runtime failure.","triggerScenarios":"Running `kops update cluster` (or any target that triggers model building) when a spec EtcdClusters entry has no `backups.backupStore` set (Backups nil, or Backups.BackupStore empty string).","commonSituations":"Hand-written or migrated cluster manifests that omit the backups block; older cluster specs predating etcd-manager defaults; templating tools that strip empty fields from the spec.","solutions":["Add `backups: {backupStore: <state-store path, e.g. s3://bucket/cluster/backups/etcd-main>}` to each etcdCluster in the cluster spec.","Re-create the spec via `kops create cluster` (which populates backupStore automatically) and re-apply your customizations.","If you did not intend etcd-manager, check for leftover etcdClusters entries from a legacy (non-manager) cluster and remove or migrate them."],"exampleFix":"// before\netcdClusters:\n- name: main\n  members:\n  - instanceGroup: master-a\n// after\netcdClusters:\n- name: main\n  backups:\n    backupStore: s3://my-kops-state/mycluster/backups/etcd-main\n  members:\n  - instanceGroup: master-a","handlingStrategy":"validation","validationCode":"for _, c := range cluster.Spec.EtcdClusters {\n\tif c.Backups == nil || c.Backups.BackupStore == \"\" {\n\t\treturn fmt.Errorf(\"etcd cluster %q missing backups.backupStore\", c.Name)\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err := validateBackupStores(cluster); err != nil { return fmt.Errorf(\"cluster spec invalid: %w\", err) }","preventionTips":["Always generate specs with `kops create cluster`, which sets backupStore from the state store.","Lint cluster YAML for non-empty backups.backupStore before `kops replace`.","Never strip zero-value-looking fields from the spec with generic templating."],"tags":["kops","etcd-manager","cluster-spec","config-validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}