{"record":{"id":"1cf01b997f1b85ba","repo":"kubernetes/kops","slug":"parsing-storageaccountid-w","errorCode":null,"errorMessage":"parsing StorageAccountID: %w","messagePattern":"parsing StorageAccountID: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/apply_cluster.go","lineNumber":783,"sourceCode":"\t\t\ttarget = linode.NewAPITarget(cloud.(linode.LinodeCloud))\n\t\tcase kops.CloudProviderMetal:\n\t\t\ttarget = metal.NewAPITarget(cloud.(*metal.Cloud), nil)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"direct configuration not supported with CloudProvider:%q\", cluster.GetCloudProvider())\n\t\t}\n\n\tcase TargetTerraform:\n\t\toutDir := c.OutDir\n\t\ttf := terraform.NewTerraformTarget(cloud, project, outDir, cluster.Spec.Target)\n\n\t\t// Register an azurerm provider alias for state storage blobs.\n\t\t// If the storage account is in a different subscription, pass subscription_id.\n\t\tif azureSpec := cluster.Spec.CloudProvider.Azure; azureSpec != nil {\n\t\t\targs := map[string]string{}\n\t\t\tif azureSpec.StorageAccountID != \"\" {\n\t\t\t\tstorageAccountID, err := arm.ParseResourceID(azureSpec.StorageAccountID)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"parsing StorageAccountID: %w\", err)\n\t\t\t\t}\n\t\t\t\tif storageAccountID.SubscriptionID != azureSpec.SubscriptionID {\n\t\t\t\t\targs[\"subscription_id\"] = storageAccountID.SubscriptionID\n\t\t\t\t}\n\t\t\t}\n\t\t\ttf.AzureStorageAccountID = azureSpec.StorageAccountID\n\t\t\ttf.EnsureTerraformProvider(\"azurerm\", args)\n\t\t}\n\n\t\t// We include a few \"util\" variables in the TF output\n\t\tif err := tf.AddOutputVariable(\"region\", terraformWriter.LiteralFromStringValue(cloud.Region())); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif project != \"\" {\n\t\t\tif err := tf.AddOutputVariable(\"project\", terraformWriter.LiteralFromStringValue(project)); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}","sourceCodeStart":765,"sourceCodeEnd":801,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/apply_cluster.go#L765-L801","documentation":"kops wraps arm.ParseResourceID failures while building the Terraform target for Azure clusters. The cluster spec's spec.cloudProvider.azure.storageAccountID must be a fully-qualified Azure Resource Manager resource ID (e.g. /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<name>); anything else (account name, URL, typo) fails to parse and the apply aborts with this wrapped error.","triggerScenarios":"Running kops with --target=terraform on an Azure cluster whose spec.cloudProvider.azure.storageAccountID is set to a value arm.ParseResourceID cannot parse — e.g. a bare storage account name, a blob endpoint URL, a wrong-cased or truncated resource ID path.","commonSituations":"Users paste the storage account name instead of its resource ID; copying the ID from the Azure portal with the 'subscriptions' segment misspelled; hand-editing the cluster spec and omitting the /subscriptions/<id>/ prefix; using an az CLI output field like primaryEndpoints blob URL.","solutions":["Set spec.cloudProvider.azure.storageAccountID to the full ARM resource ID, e.g. /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>","Get the correct ID with: az storage account show -n <account> -g <rg> --query id -o tsv","Clear the field entirely if the default (same-subscription) storage account behavior is intended — the check only runs when the value is non-empty","Re-run kops update cluster --target=terraform to confirm parsing succeeds"],"exampleFix":"// before (cluster.yaml)\nspec:\n  cloudProvider:\n    azure:\n      storageAccountID: mystorageaccount1\n// after\nspec:\n  cloudProvider:\n    azure:\n      storageAccountID: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/kops-rg/providers/Microsoft.Storage/storageAccounts/mystorageaccount1","handlingStrategy":"validation","validationCode":"func validAzureStorageAccountID(id string) bool {\n\tre := regexp.MustCompile(`^/subscriptions/[0-9a-fA-F-]{36}/resourceGroups/[^/]+/providers/Microsoft\\.Storage/storageAccounts/[^/]+$`)\n\treturn id == \"\" || re.MatchString(id)\n}\n// check before apply:\nif !validAzureStorageAccountID(cluster.Spec.CloudProvider.Azure.StorageAccountID) {\n\treturn fmt.Errorf(\"storageAccountID must be a full ARM resource ID\")\n}","typeGuard":"func isARMResourceID(s string) bool {\n\treturn strings.HasPrefix(s, \"/subscriptions/\") && strings.Contains(s, \"/providers/\")\n}","tryCatchPattern":null,"preventionTips":["Always copy the resource ID (not the name) from az storage account show --query id","Store the full ARM ID in the cluster spec, never a bare account name","Validate the spec with kops toolbox template or a linter before apply","Leave the field empty if you don't need a cross-subscription storage account"],"tags":["azure","terraform","config-validation"],"backgroundTag":"invalid-azure-resource-id","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"}