{"record":{"id":"d195c333378aad9e","repo":"kubernetes/kops","slug":"error-deleting-server-group-v","errorCode":null,"errorMessage":"error deleting server group: %v","messagePattern":"error deleting server group: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/openstack/server_group.go","lineNumber":147,"sourceCode":"\t\t\tklog.Warningf(\"Unable to find fixed ip for %s: %v\", instance.Name, err)\n\t\t}\n\n\t\tcm.PrivateIP = ip\n\t\tcm.Roles = []string{instance.Metadata[\"KopsRole\"]}\n\t\tcm.State = cloudinstances.State(instance.Status)\n\t}\n\treturn cg, nil\n}\n\nfunc (c *openstackCloud) DeleteServerGroup(groupID string) error {\n\treturn deleteServerGroup(c, groupID)\n}\n\nfunc deleteServerGroup(c OpenstackCloud, groupID string) error {\n\tdone, err := vfs.RetryWithBackoff(deleteBackoff, func() (bool, error) {\n\t\terr := servergroups.Delete(context.TODO(), c.ComputeClient(), groupID).ExtractErr()\n\t\tif err != nil && !isNotFound(err) {\n\t\t\treturn false, fmt.Errorf(\"error deleting server group: %v\", err)\n\t\t}\n\t\tif isNotFound(err) {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t} else if done {\n\t\treturn nil\n\t} else {\n\t\treturn wait.ErrWaitTimeout\n\t}\n}\n","sourceCodeStart":129,"sourceCodeEnd":162,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/openstack/server_group.go#L129-L162","documentation":"deleteServerGroup calls the Nova servergroups.Delete API. Errors are wrapped as \"error deleting server group: %v\" unless the error is a 404 (isNotFound), which is treated as success because the desired end state (group gone) is already reached. After deleteBackoff retries are exhausted, the wrapped error propagates.","triggerScenarios":"servergroups.Delete(...).ExtractErr() returns a non-404 error: 403 because the server group still has members or belongs to another project, 404 handled as success (not this error), 401 expired token, 409 conflict (group busy/being modified), or network failure to the compute endpoint.","commonSituations":"Tearing down a cluster whose server group still contains running instances the cloud forbids deleting; cross-project/role misconfiguration so the token cannot delete resources; nova-api outage during kops delete cluster; a hard 409 while another process mutates the group.","solutions":["Delete remaining instances in the server group first ('openstack server list --group <group-id>' then delete them), then retry.","Check auth/roles: ensure the credentials own the server group and have compute:os-server-groups delete permissions.","Read the wrapped HTTP status: 409 -> wait for in-flight operations on the group to finish; 401 -> refresh credentials.","If the group is already gone, ignore — isNotFound maps it to success; verify with 'openstack server group show <group-id>'.","Retry after transient nova-api failures; the internal backoff already retries persistent 5xx."],"exampleFix":"// before: deleting group while instances still exist -> 403/409\nif err := cloud.DeleteServerGroup(group.ID); err != nil { return err }\n// after: drain members first\nfor _, inst := range membersOfGroup(group.ID) {\n\tif err := deleteServer(instance.ID); err != nil { return err }\n}\nif err := cloud.DeleteServerGroup(group.ID); err != nil { return err }","handlingStrategy":"try-catch","validationCode":"// Check group membership and ownership before deleting\nmembers, _ := listServersInGroup(groupID)\nif len(members) > 0 {\n\treturn fmt.Errorf(\"server group %s still has %d members; delete instances first\", groupID, len(members))\n}","typeGuard":null,"tryCatchPattern":"err := cloud.DeleteServerGroup(groupID)\nif err != nil {\n\tvar gerr gophercloud.ErrUnexpectedResponseCode\n\tif errors.As(err, &gerr) {\n\t\tswitch gerr.Actual {\n\t\tcase 403, 409:\n\t\t\treturn fmt.Errorf(\"server group %s is busy or owned elsewhere; drain members and check permissions: %w\", groupID, err)\n\t\tcase 404:\n\t\t\treturn nil // already gone\n\t\t}\n\t}\n\tif errors.Is(err, wait.ErrWaitTimeout) {\n\t\treturn fmt.Errorf(\"server group %s deletion timed out after retries\", groupID)\n\t}\n\treturn err\n}","preventionTips":["Always drain/delete instances in a server group before deleting the group.","Use credentials scoped to the project owning the server group.","Handle 404 as success in callers since deleteServerGroup already tolerates it.","Serialize teardown steps so no other process mutates the group concurrently (avoids 409)."],"tags":["openstack","nova","server-group","deletion","api-error"],"backgroundTag":"openstack-api-request-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}