kubernetes/kops · error

parsing etcd backup-store %q: %w

Error message

parsing etcd backup-store %q: %w

What it means

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'.

Source

Thrown at pkg/model/components/etcdmanager/model.go:66

)

// resolveAzureBackupStore rewrites azureblob://<account>/<container>/<key> into
// the legacy azureblob://<container>/<key> shape understood by the pinned
// etcd-manager image, returning the storage account derived from
// configStoreBase (the single source of truth for the cluster) for
// AZURE_STORAGE_ACCOUNT injection. Non-azureblob backup stores pass through
// unchanged. Errors if a backup store is azureblob:// but configStoreBase is
// not, since validation already enforces account uniformity.
//
// TODO: remove once etcd-manager is bumped to a release whose vendored VFS
// understands azureblob://<account>/<container>/<key>.
func resolveAzureBackupStore(configStoreBase, backupStore string) (legacyURL string, storageAccount string, err error) {
	if !strings.HasPrefix(backupStore, "azureblob://") {
		return backupStore, "", nil
	}
	bp, err := vfs.Context.BuildVfsPath(backupStore)
	if err != nil {
		return "", "", fmt.Errorf("parsing etcd backup-store %q: %w", backupStore, err)
	}
	bpAzure, ok := bp.(*vfs.AzureBlobPath)
	if !ok {
		return "", "", fmt.Errorf("expected azureblob:// backup-store, got %q", backupStore)
	}
	csp, err := vfs.Context.BuildVfsPath(configStoreBase)
	if err != nil {
		return "", "", fmt.Errorf("parsing configStore.base %q: %w", configStoreBase, err)
	}
	csAzure, ok := csp.(*vfs.AzureBlobPath)
	if !ok {
		return "", "", fmt.Errorf("backup-store %q is azureblob:// but configStore.base %q is not", backupStore, configStoreBase)
	}
	legacy := "azureblob://" + bpAzure.Container()
	if bpAzure.Key() != "" {
		legacy += "/" + bpAzure.Key()
	}
	return legacy, csAzure.Account(), nil

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Fix the azureblob:// backupStore URL (azureblob://<account>/<container>[/<key>]) in the etcd cluster spec
  2. Check the wrapped inner error for the exact parse failure
  3. Validate the storage account/container names against Azure naming rules

Example fix

// before
backups:
  backupStore: "azureblob:///bad url"
// after
backups:
  backupStore: "azureblob://myaccount/etcd-backups/main"
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasPrefix(backupStore, "azureblob://") {
    rest := strings.TrimPrefix(backupStore, "azureblob://")
    if rest == "" || strings.ContainsAny(rest, " ?#") {
        return fmt.Errorf("malformed azureblob backupStore: %q", backupStore)
    }
}

Type guard

null

Try / catch

legacy, account, err := resolveAzureBackupStore(configStoreBase, backupStore)
if err != nil {
    if strings.Contains(err.Error(), "parsing etcd backup-store") {
        // correct the backupStore URI and retry
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/5bd0842048b61ccf. Report an issue: GitHub.