{"record":{"id":"aee658a6c778c3ce","repo":"kubernetes/kops","slug":"volume-tag-split-failed-too-few-components-for-ta","errorCode":null,"errorMessage":"volume tag split failed, too few components for tag %q on volume %q","messagePattern":"volume tag split failed, too few components for tag %q on volume %q","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/do/cloud.go","lineNumber":349,"sourceCode":"\t\tvolumeID := volume.ID\n\n\t\tetcdClusterName := \"\"\n\t\tvar etcdClusterSpec *etcd.EtcdClusterSpec\n\n\t\tfor _, myTag := range volume.Tags {\n\t\t\tklog.V(8).Infof(\"findEtcdStatus status (from cloud): checking if volume with tag %q belongs to cluster\", myTag)\n\t\t\t// check if volume belongs to this cluster.\n\t\t\t// tag will be in the format \"KubernetesCluster:dev5-k8s-local\" (where clusterName is dev5.k8s.local)\n\t\t\tclusterName := strings.ReplaceAll(cluster.Name, \".\", \"-\")\n\t\t\tif strings.Contains(myTag, fmt.Sprintf(\"%s:%s\", TagKubernetesClusterNamePrefix, clusterName)) {\n\t\t\t\tklog.V(10).Infof(\"findEtcdStatus cluster comparison matched for tag: %v\", myTag)\n\t\t\t\t// this volume belongs to our cluster, add this to our etcdClusterSpec.\n\t\t\t\t// loop through the tags again and\n\t\t\t\tfor _, volumeTag := range volume.Tags {\n\t\t\t\t\tif strings.Contains(volumeTag, TagKubernetesClusterIndex) {\n\t\t\t\t\t\tvolumeTagParts := strings.Split(volumeTag, \":\")\n\t\t\t\t\t\tif len(volumeTagParts) < 2 {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"volume tag split failed, too few components for tag %q on volume %q\", volumeTag, volume)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdropletIndex := volumeTagParts[1]\n\t\t\t\t\t\tetcdClusterSpec, err = c.getEtcdClusterSpec(volume.Name, dropletIndex)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"error parsing etcd cluster tag %q on volume %q: %v\", volumeTag, volumeID, err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tklog.V(10).Infof(\"findEtcdStatus etcdClusterSpec: %v\", fi.DebugAsJsonString(etcdClusterSpec))\n\t\t\t\t\t\tetcdClusterName = etcdClusterSpec.ClusterKey\n\t\t\t\t\t\tstatus := statusMap[etcdClusterName]\n\t\t\t\t\t\tif status == nil {\n\t\t\t\t\t\t\tstatus = &kops.EtcdClusterStatus{\n\t\t\t\t\t\t\t\tName: etcdClusterName,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstatusMap[etcdClusterName] = status\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmemberName := etcdClusterSpec.NodeName","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/do/cloud.go#L331-L367","documentation":"For each tagged etcd volume, findEtcdStatus looks for a tag containing TagKubernetesClusterIndex (the droplet index marker) and splits it on ':' expecting at least two parts ('<prefix>:<index>'). If the tag has no colon-separated index component, it aborts with this error because the droplet index cannot be extracted for getEtcdClusterSpec.","triggerScenarios":"A volume in the cluster belongs to the cluster (cluster tag matched earlier) but carries a malformed index tag — e.g. tag is just the prefix with no ':N' suffix, tags were edited manually, or volumes were created by a different/kOps version writing a different tag format.","commonSituations":"Hand-edited DO volume tags; volumes reused/imported from another cluster or tooling; upgrading kOps across versions where tag naming changed; typos when seeding etcd volumes manually.","solutions":["Inspect the offending volume's tags (`doctl compute volume list`) and correct the index tag to '<prefix>:<index>' format.","Exclude/fix volumes that belong to a different cluster but carry a partial tag set.","Restore consistent tagging by letting kOps recreate the affected etcd volume (only if data loss is acceptable — etcd data is on it).","Verify the kOps version writing tags matches the version reading them; avoid manual tag edits."],"exampleFix":"// before\ntags = [\"kubernetes.io/cluster/mycluster\"]\n// after\ntags = [\"kubernetes.io/cluster/mycluster\", \"kubernetes.io/cluster/mycluster:1\"]  // must include \":<dropletIndex>\"","handlingStrategy":"validation","validationCode":"for _, tag := range volume.Tags {\n    if strings.Contains(tag, TagKubernetesClusterIndex) && len(strings.Split(tag, \":\")) < 2 {\n        return fmt.Errorf(\"malformed index tag %q on volume %s\", tag, volume.ID)\n    }\n}","typeGuard":null,"tryCatchPattern":"status, err := cloud.FindClusterStatus(cluster)\nif err != nil && strings.Contains(err.Error(), \"tag split failed\") {\n    return auditAndFixVolumeTags(cluster) // repair or ignore offending volume\n}","preventionTips":["Never hand-edit DO volume tags on kOps-managed volumes.","Keep the kOps version that reads tags consistent with the one that wrote them.","Audit tags with doctl after any manual DR/recovery work.","Exclude volumes from other tooling that reuse the cluster tag prefix."],"tags":["digitalocean","storage","etcd","tag-validation"],"backgroundTag":"malformed-tag-format","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"}