{"record":{"id":"abc408f2af773836","repo":"kubernetes/kops","slug":"error-deleting-security-group-v","errorCode":null,"errorMessage":"error deleting security group: %v","messagePattern":"error deleting security group: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/openstack/security_group.go","lineNumber":143,"sourceCode":"\t})\n\tif err != nil {\n\t\treturn rule, err\n\t} else if done {\n\t\treturn rule, nil\n\t} else {\n\t\treturn rule, wait.ErrWaitTimeout\n\t}\n}\n\nfunc (c *openstackCloud) DeleteSecurityGroup(sgID string) error {\n\treturn deleteSecurityGroup(c, sgID)\n}\n\nfunc deleteSecurityGroup(c OpenstackCloud, sgID string) error {\n\tdone, err := vfs.RetryWithBackoff(deleteBackoff, func() (bool, error) {\n\t\terr := sg.Delete(context.TODO(), c.NetworkingClient(), sgID).ExtractErr()\n\t\tif err != nil && !isNotFound(err) {\n\t\t\treturn false, fmt.Errorf(\"error deleting security 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\nfunc (c *openstackCloud) DeleteSecurityGroupRule(ruleID string) error {\n\treturn deleteSecurityGroupRule(c, ruleID)\n}","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/openstack/security_group.go#L125-L161","documentation":"This error is returned by deleteSecurityGroup when the Neutron security-group Delete API fails with an error other than 404 Not Found, inside the deleteBackoff retry loop. A 404 is deliberately treated as success (already deleted), so this error signals a real failure: the group is still in use, permissions are missing, or the API is unreachable. The error is retried per backoff policy and then propagated.","triggerScenarios":"sg.Delete(...).ExtractErr() returns an error where isNotFound(err) is false — most commonly HTTP 409 because the security group still has members/rules or is the default group, or 403/401 auth/RBAC failures.","commonSituations":"Trying to delete a security group that still has interfaces attached or rules referencing it, attempting to delete the project's default security group, teardown running with stale or insufficient credentials.","solutions":["Check the wrapped status: on 409 delete the group's rules/members first (deleteSecurityGroupRule) or wait for instances to detach","Never delete the project's default security group; skip it explicitly","On 401/403 refresh credentials and confirm the project/region in the cloud config","If transient (5xx/429), let the retry backoff handle it or rerun teardown"],"exampleFix":"// before: delete rules implicitly via group delete\nerr := sg.Delete(context.TODO(), c.NetworkingClient(), sgID).ExtractErr()\n// after: remove dependent rules first\nrules, err := listSecurityGroupRules(c, sgr.ListOpts{SecurityGroupID: sgID})\nif err != nil { return err }\nfor _, r := range rules {\n\tif err := deleteSecurityGroupRule(c, r.ID); err != nil { return err }\n}\nerr = sg.Delete(context.TODO(), c.NetworkingClient(), sgID).ExtractErr()","handlingStrategy":"try-catch","validationCode":"sg, err := groups.Get(ctx, cloud.NetworkingClient(), sgID).Extract()\nif err != nil {\n\tif gophercloud.ResponseCodeIs(err, 404) { return nil } // already gone\n\treturn err\n}\nif sg.Name == \"default\" {\n\treturn fmt.Errorf(\"refusing to delete the default security group %q\", sgID)\n}","typeGuard":"func isNotFoundErr(err error) bool {\n\tvar nf gophercloud.ErrDefault404\n\treturn errors.As(err, &nf)\n}","tryCatchPattern":"err := deleteSecurityGroup(c, sgID)\nif err != nil {\n\tif isNotFoundErr(err) { return nil }\n\tif strings.Contains(err.Error(), \"409\") {\n\t\t// delete child rules / wait for detachment, then retry once\n\t}\n\treturn fmt.Errorf(\"deleting sg %s: %w\", sgID, err)\n}","preventionTips":["Delete security group rules and detach instances before deleting the group","Never attempt to delete the project's default security group","Ensure teardown credentials have networking delete permissions","Treat 404 as success to keep teardown idempotent (the code already does this)"],"tags":["openstack","neutron","security-group","deletion-failed"],"backgroundTag":"openstack-resource-in-use-409","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"}