{"record":{"id":"dbec4f1cd05349a8","repo":"kubernetes/kops","slug":"expected-azureblob-url-got-q","errorCode":null,"errorMessage":"expected azureblob:// URL, got %q","messagePattern":"expected azureblob:// URL, got %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apis/kops/validation/validation.go","lineNumber":1660,"sourceCode":"\t}\n\n\treturn allErrs\n}\n\n// azureBlobAccount returns the storage account encoded in an azureblob:// URL,\n// or \"\" with no error if the URL is not azureblob://. Returns an error only if\n// the URL has the azureblob:// prefix but fails to parse.\nfunc azureBlobAccount(rawURL string) (string, error) {\n\tif !strings.HasPrefix(rawURL, \"azureblob://\") {\n\t\treturn \"\", nil\n\t}\n\tp, err := vfs.Context.BuildVfsPath(rawURL)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tazPath, ok := p.(*vfs.AzureBlobPath)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"expected azureblob:// URL, got %q\", rawURL)\n\t}\n\treturn azPath.Account(), nil\n}\n\n// validateAzureBlobAccountUniformity enforces that every azureblob:// URL in\n// the cluster spec uses the same storage account as configStore.base. Any\n// azureblob:// URL elsewhere in the spec is rejected when configStore.base is\n// not itself azureblob://.\nfunc validateAzureBlobAccountUniformity(spec *kops.ClusterSpec, fieldPath *field.Path) field.ErrorList {\n\tvar allErrs field.ErrorList\n\tcsPath := fieldPath.Child(\"configStore\")\n\n\tcanonical := \"\"\n\tif strings.HasPrefix(spec.ConfigStore.Base, \"azureblob://\") {\n\t\taccount, err := azureBlobAccount(spec.ConfigStore.Base)\n\t\tif err != nil {\n\t\t\tallErrs = append(allErrs, field.Invalid(csPath.Child(\"base\"), spec.ConfigStore.Base, err.Error()))\n\t\t\treturn allErrs","sourceCodeStart":1642,"sourceCodeEnd":1678,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/apis/kops/validation/validation.go#L1642-L1678","documentation":"azureBlobAccount builds a vfs path from a raw azureblob:// URL and asserts the result is an *vfs.AzureBlobPath. If vfs.Context.BuildVfsPath returns a different path type (or the URL is not a valid azureblob URL), the function cannot extract a storage account name and returns this error. It is used by validateAzureBlobAccountUniformity to compare storage accounts across the cluster spec.","triggerScenarios":"Passing a non-azureblob URL (e.g. s3://, file://, or a malformed azureblob:// string) into azureBlobAccount; BuildVfsPath parses it into a different vfs.Path concrete type so the type assertion fails.","commonSituations":"Configuring configBase or a mirror with the wrong scheme when migrating a cluster to Azure; copy-pasting an S3 or Azure Files (file://) URL; a typo like azureblob:/account (single slash) that parses as something else.","solutions":["Use a well-formed URL of the form azureblob://<account>/<container>/<path> for all cluster storage locations.","Verify the scheme is exactly `azureblob://` (two slashes) and that vfs can parse it (test with `kops get cluster` or a small vfs.Context.BuildVfsPath call).","If uniformity validation fails, ensure every azureblob:// URL in the spec uses the same storage account as configStore.base."],"exampleFix":"// before\nconfigBase: s3://my-bucket/cluster.example.com\n// after\nconfigBase: azureblob://mystorageaccount/kops/cluster.example.com","handlingStrategy":"type-guard","validationCode":"u, err := url.Parse(rawURL)\nif err != nil || u.Scheme != \"azureblob\" {\n    return fmt.Errorf(\"not an azureblob URL: %q\", rawURL)\n}","typeGuard":"func isAzureBlobPath(p vfs.Path) (*vfs.AzureBlobPath, bool) {\n    az, ok := p.(*vfs.AzureBlobPath)\n    return az, ok\n}","tryCatchPattern":null,"preventionTips":["Standardize on azureblob://<account>/<container>/<path> for all cluster storage fields.","Validate URLs with vfs.Context.BuildVfsPath in CI before applying cluster changes.","When migrating from S3/GCS, sed-check every URL field for leftover schemes."],"tags":["kops","azure","vfs","url-validation"],"backgroundTag":"invalid-url-scheme","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"}