{"record":{"id":"de985ec438fdfc1b","repo":"kubernetes/kops","slug":"could-not-delete-server-group-q-v","errorCode":null,"errorMessage":"could not delete server group %q: %v","messagePattern":"could not delete server group %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/openstack/cloud.go","lineNumber":684,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\n\tsgName := g.InstanceGroup.Name\n\tif name, ok := g.InstanceGroup.Annotations[OS_ANNOTATION+SERVER_GROUP_NAME]; ok {\n\t\tsgName = name\n\t}\n\tsgs, err := c.ListServerGroups(servergroups.ListOpts{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not list server groups %v\", err)\n\t}\n\n\tfor _, sg := range sgs {\n\t\tif fmt.Sprintf(\"%s-%s\", cluster.Name, sgName) == sg.Name {\n\t\t\tif len(sg.Members) == 0 {\n\t\t\t\terr = c.DeleteServerGroup(sg.ID)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"could not delete server group %q: %v\", sg.ID, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tklog.Infof(\"Server group %q still has members (IDs: %s), delete not executed\", sg.ID, strings.Join(sg.Members, \", \"))\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *openstackCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {\n\treturn getCloudGroups(c, cluster, instancegroups, warnUnmatched, nodes)\n}\n\nfunc getCloudGroups(c OpenstackCloud, cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {\n\tnodeMap := cloudinstances.GetNodeMap(nodes, cluster)\n\tgroups := make(map[string]*cloudinstances.CloudInstanceGroup)\n\tfor _, ig := range instancegroups {","sourceCodeStart":666,"sourceCodeEnd":702,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/openstack/cloud.go#L666-L702","documentation":"Wrapped error returned when deleting an empty OpenStack server group fails during instance-group teardown. kOps only deletes a server group with zero members; if Nova rejects DeleteServerGroup(sg.ID), the cleanup aborts with the group ID and cause.","triggerScenarios":"c.DeleteServerGroup(sg.ID) returns an error, typically 404 (group already deleted), 409 (members appeared between listing and delete), or permission/endpoint failure.","commonSituations":"Race where an instance was scheduled into the group after the member check; group deleted concurrently by another kops run or operator; insufficient RBAC policy on the compute API.","solutions":["Re-run the delete once the race settles; the wrapped error shows the HTTP status","Confirm the group is empty with `openstack server group show <id>` then delete manually","Check Nova policy.json/RBAC allows server group deletion for the user","If 404, the group is already gone and cleanup effectively succeeded"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"sg, err := getServerGroupByName(cluster.Name, sgName)\nif err == nil && len(sg.Members) > 0 { return fmt.Errorf(\"server group %s still has members\", sg.ID) }","typeGuard":null,"tryCatchPattern":"if err := c.DeleteServerGroup(sg.ID); err != nil {\n    var gErr gophercloud.ErrUnexpectedResponseCode\n    if errors.As(err, &gErr) && (gErr.Actual == 404 || gErr.Actual == 409) { /* re-check and retry */ }\n    return fmt.Errorf(\"could not delete server group %q: %v\", sg.ID, err)\n}","preventionTips":["Re-read members immediately before delete to narrow the race window","Serialize kops delete runs","Grant the user compute:server_group delete RBAC"],"tags":["openstack","nova","server-groups","teardown"],"backgroundTag":"openstack-resource-deletion-failed","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"}