{"record":{"id":"d1d8fc4eac6c21be","repo":"kubernetes/kops","slug":"deleting-vmss-w","errorCode":null,"errorMessage":"deleting VMSS: %w","messagePattern":"deleting VMSS: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/azure/vmscaleset.go","lineNumber":91,"sourceCode":"\t}\n\treturn l, nil\n}\n\nfunc (c *vmScaleSetsClientImpl) Get(ctx context.Context, resourceGroupName string, vmssName string) (*compute.VirtualMachineScaleSet, error) {\n\topts := &compute.VirtualMachineScaleSetsClientGetOptions{\n\t\tExpand: to.Ptr(compute.ExpandTypesForGetVMScaleSetsUserData),\n\t}\n\tresp, err := c.c.Get(ctx, resourceGroupName, vmssName, opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting VMSS: %w\", err)\n\t}\n\treturn &resp.VirtualMachineScaleSet, nil\n}\n\nfunc (c *vmScaleSetsClientImpl) Delete(ctx context.Context, resourceGroupName, vmssName string) error {\n\tfuture, err := c.c.BeginDelete(ctx, resourceGroupName, vmssName, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"deleting VMSS: %w\", err)\n\t}\n\tif _, err := future.PollUntilDone(ctx, nil); err != nil {\n\t\treturn fmt.Errorf(\"waiting for VMSS deletion completion: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc newVMScaleSetsClientImpl(subscriptionID string, cred *azidentity.DefaultAzureCredential) (*vmScaleSetsClientImpl, error) {\n\tc, err := compute.NewVirtualMachineScaleSetsClient(subscriptionID, cred, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating VMSSs client: %w\", err)\n\t}\n\treturn &vmScaleSetsClientImpl{\n\t\tc: c,\n\t}, nil\n}\n","sourceCodeStart":73,"sourceCodeEnd":108,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/vmscaleset.go#L73-L108","documentation":"This error wraps the immediate failure of the ARM BeginDelete call that starts deleting a Virtual Machine Scale Set. It fires synchronously when Azure rejects the delete request (auth, RBAC, invalid name, or ARM rejection) — not during polling. The original SDK error is preserved via %w.","triggerScenarios":"vmScaleSetsClientImpl.Delete calls compute.VirtualMachineScaleSetsClient.BeginDelete and the request itself fails: identity lacks 'Contributor'/'Virtual Machine Contributor' role, VMSS already gone in a racy delete, resource group name mismatch, or the request never reaches ARM (network/auth failure).","commonSituations":"Tearing down a cluster while an operator with insufficient RBAC runs kops delete cluster; concurrent delete pipelines racing to remove the same VMSS; deleting a scale set whose parent resource group is mid-deletion; expired azidentity token or misconfigured AZURE_* env vars.","solutions":["Unwrap with errors.As (*azcore.ResponseError); if StatusCode==404/409, treat as already-deleted or retry idempotently","Grant the kOps identity 'Virtual Machine Contributor' on the resource group","Check for concurrent deletes (two CI jobs / reconciliation loops) and add a mutex or retry-on-conflict","Re-authenticate: refresh credentials and verify AZURE_TENANT_ID/AZURE_CLIENT_ID/AZURE_CLIENT_SECRET or managed identity","Retry the delete after transient failures; BeginDelete is idempotent for an existing VMSS"],"exampleFix":"// before\nerr := client.Delete(ctx, rg, vmssName)\nif err != nil { return err }\n// after\nerr := client.Delete(ctx, rg, vmssName)\nif err != nil {\n\tvar respErr *azcore.ResponseError\n\tif errors.As(err, &respErr) && respErr.StatusCode == http.StatusNotFound {\n\t\treturn nil // already deleted\n\t}\n\treturn fmt.Errorf(\"deleting VMSS %q: %w\", vmssName, err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: confirm existence and RBAC preconditions before deleting\nvmss, err := client.Get(ctx, rg, vmssName)\nif err != nil {\n\tif isNotFoundErr(err) { return nil } // nothing to delete\n\treturn err\n}","typeGuard":"func isConflictOrNotFound(err error) bool {\n\tvar respErr *azcore.ResponseError\n\treturn errors.As(err, &respErr) && (respErr.StatusCode == http.StatusNotFound || respErr.StatusCode == http.StatusConflict)\n}","tryCatchPattern":"err := client.Delete(ctx, rg, vmssName)\nif err != nil {\n\tvar respErr *azcore.ResponseError\n\tif errors.As(err, &respErr) {\n\t\tswitch respErr.StatusCode {\n\t\tcase 404:\n\t\t\treturn nil // already deleted — treat as success\n\t\tcase 409, 429:\n\t\t\t// retry with backoff / serialize concurrent deletes\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"deleting VMSS: %w\", err)\n\t\t}\n\t}\n}","preventionTips":["Avoid concurrent delete pipelines for the same VMSS (serialize teardown jobs)","Treat 404 on delete as success for idempotent teardown","Grant 'Virtual Machine Contributor' so BeginDelete is never RBAC-rejected","Use retry with exponential backoff on 409/429 responses","Keep credentials fresh for long-running teardown operations"],"tags":["azure","vmss","delete","rbac","error-wrapping"],"backgroundTag":"azure-sdk-request-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"}