{"record":{"id":"5bd0842048b61ccf","repo":"kubernetes/kops","slug":"parsing-etcd-backup-store-q-w","errorCode":null,"errorMessage":"parsing etcd backup-store %q: %w","messagePattern":"parsing etcd backup-store %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/components/etcdmanager/model.go","lineNumber":66,"sourceCode":")\n\n// resolveAzureBackupStore rewrites azureblob://<account>/<container>/<key> into\n// the legacy azureblob://<container>/<key> shape understood by the pinned\n// etcd-manager image, returning the storage account derived from\n// configStoreBase (the single source of truth for the cluster) for\n// AZURE_STORAGE_ACCOUNT injection. Non-azureblob backup stores pass through\n// unchanged. Errors if a backup store is azureblob:// but configStoreBase is\n// not, since validation already enforces account uniformity.\n//\n// TODO: remove once etcd-manager is bumped to a release whose vendored VFS\n// understands azureblob://<account>/<container>/<key>.\nfunc resolveAzureBackupStore(configStoreBase, backupStore string) (legacyURL string, storageAccount string, err error) {\n\tif !strings.HasPrefix(backupStore, \"azureblob://\") {\n\t\treturn backupStore, \"\", nil\n\t}\n\tbp, err := vfs.Context.BuildVfsPath(backupStore)\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"parsing etcd backup-store %q: %w\", backupStore, err)\n\t}\n\tbpAzure, ok := bp.(*vfs.AzureBlobPath)\n\tif !ok {\n\t\treturn \"\", \"\", fmt.Errorf(\"expected azureblob:// backup-store, got %q\", backupStore)\n\t}\n\tcsp, err := vfs.Context.BuildVfsPath(configStoreBase)\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"parsing configStore.base %q: %w\", configStoreBase, err)\n\t}\n\tcsAzure, ok := csp.(*vfs.AzureBlobPath)\n\tif !ok {\n\t\treturn \"\", \"\", fmt.Errorf(\"backup-store %q is azureblob:// but configStore.base %q is not\", backupStore, configStoreBase)\n\t}\n\tlegacy := \"azureblob://\" + bpAzure.Container()\n\tif bpAzure.Key() != \"\" {\n\t\tlegacy += \"/\" + bpAzure.Key()\n\t}\n\treturn legacy, csAzure.Account(), nil","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/components/etcdmanager/model.go#L48-L84","documentation":"resolveAzureBackupStore handles etcd backup stores on Azure by parsing the azureblob:// backup-store URL into a vfs.AzureBlobPath to derive the legacy URL. If vfs.Context.BuildVfsPath fails to parse the backupStore string, the error is wrapped as 'parsing etcd backup-store'.","triggerScenarios":"An etcd cluster spec on Azure with a backupStore starting with azureblob:// that is malformed (bad container/key syntax) so BuildVfsPath returns an error during buildPod.","commonSituations":"Hand-edited etcdClusters backups config; mistyped container name; unsupported characters in the blob path; config generated by an older kOps version with an incompatible URL form.","solutions":["Fix the azureblob:// backupStore URL (azureblob://<account>/<container>[/<key>]) in the etcd cluster spec","Check the wrapped inner error for the exact parse failure","Validate the storage account/container names against Azure naming rules"],"exampleFix":"// before\nbackups:\n  backupStore: \"azureblob:///bad url\"\n// after\nbackups:\n  backupStore: \"azureblob://myaccount/etcd-backups/main\"","handlingStrategy":"validation","validationCode":"if strings.HasPrefix(backupStore, \"azureblob://\") {\n    rest := strings.TrimPrefix(backupStore, \"azureblob://\")\n    if rest == \"\" || strings.ContainsAny(rest, \" ?#\") {\n        return fmt.Errorf(\"malformed azureblob backupStore: %q\", backupStore)\n    }\n}","typeGuard":"null","tryCatchPattern":"legacy, account, err := resolveAzureBackupStore(configStoreBase, backupStore)\nif err != nil {\n    if strings.Contains(err.Error(), \"parsing etcd backup-store\") {\n        // correct the backupStore URI and retry\n    }\n    return err\n}","preventionTips":["Validate etcd backupStore URLs in cluster specs before apply","Follow the azureblob://<account>/<container>[/<key>] format","Check wrapped inner errors for root cause"],"tags":["azure","etcd","vfs","url-parsing"],"backgroundTag":"invalid-url-syntax","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}