{"record":{"id":"62fcf743b9e843b4","repo":"kubernetes/kops","slug":"error-deleting-subnet-v","errorCode":null,"errorMessage":"error deleting subnet: %v","messagePattern":"error deleting subnet: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/openstack/subnet.go","lineNumber":113,"sourceCode":"\t})\n\tif err != nil {\n\t\treturn s, err\n\t} else if done {\n\t\treturn s, nil\n\t} else {\n\t\treturn s, wait.ErrWaitTimeout\n\t}\n}\n\nfunc (c *openstackCloud) DeleteSubnet(subnetID string) error {\n\treturn deleteSubnet(c, subnetID)\n}\n\nfunc deleteSubnet(c OpenstackCloud, subnetID string) error {\n\tdone, err := vfs.RetryWithBackoff(deleteBackoff, func() (bool, error) {\n\t\terr := subnets.Delete(context.TODO(), c.NetworkingClient(), subnetID).ExtractErr()\n\t\tif err != nil && !isNotFound(err) {\n\t\t\treturn false, fmt.Errorf(\"error deleting subnet: %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) GetExternalSubnet() (subnet *subnets.Subnet, err error) {\n\treturn getExternalSubnet(c, c.extSubnetName)\n}","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/openstack/subnet.go#L95-L131","documentation":"deleteSubnet deletes a Neutron subnet by ID inside a RetryWithBackoff(deleteBackoff) loop, tolerating 404 (already gone) via isNotFound. Any other failure is wrapped as \"error deleting subnet: %v\" and retried until backoff is exhausted. This typically means the subnet still has dependents or the API rejected the delete.","triggerScenarios":"Subnet has attached ports (instances, routers, LBs) so Neutron returns 409 conflict; RBAC denies deletion; or Neutron is unhealthy.","commonSituations":"Tearing down a cluster where VMs/ports were not yet deleted, a router interface still attached to the subnet, or manual resources sharing the subnet blocking kops destroy.","solutions":["Check the wrapped error for 409 conflict and delete dependent ports/router interfaces first: `openstack port list --subnet <id>`,`openstack router remove subnet`","Ensure no instances/load balancers still use the subnet","Retry `kops delete cluster` after dependents are removed","Verify project RBAC allows subnet deletion"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure no ports remain on the subnet before delete\nout, err := exec.Command(\"openstack\", \"port\", \"list\", \"--subnet\", subnetID, \"-f\", \"value\", \"-c\", \"ID\").Output()\nif err == nil && len(strings.TrimSpace(string(out))) > 0 {\n\tlog.Fatalf(\"subnet %s still has ports: %s\", subnetID, string(out))\n}","typeGuard":null,"tryCatchPattern":"err := deleteSubnet(cloud, subnetID)\nif err != nil {\n\tif strings.Contains(err.Error(), \"409\") || strings.Contains(err.Error(), \"conflict\") {\n\t\t// detach router interfaces / delete ports, then retry\n\t}\n\treturn err\n}","preventionTips":["Always delete instances, LBs, and router interfaces before the subnet","Use kops delete cluster rather than ad-hoc resource removal","Check `openstack router port list` for attached interfaces","Handle 404 as success for idempotent teardown"],"tags":["openstack","neutron","subnet","delete"],"backgroundTag":"resource-delete-conflict","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"}