{"record":{"id":"1e84220f92b6f727","repo":"kubernetes/kops","slug":"azure-storage-account-is-required","errorCode":null,"errorMessage":"Azure storage account is required","messagePattern":"Azure storage account is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/context.go","lineNumber":601,"sourceCode":"\taccount := strings.TrimSuffix(u.Host, \"/\")\n\tif account == \"\" {\n\t\treturn nil, fmt.Errorf(\"no storage account specified in %q; expected azureblob://<account>/<container>/<key>\", p)\n\t}\n\n\trest := strings.TrimPrefix(u.Path, \"/\")\n\tcontainer, key, _ := strings.Cut(rest, \"/\")\n\tif container == \"\" {\n\t\treturn nil, fmt.Errorf(\"no container specified in %q; expected azureblob://<account>/<container>/<key>\", p)\n\t}\n\n\treturn NewAzureBlobPath(c, account, container, key), nil\n}\n\n// getAzureBlobClient returns the client for azure blob storage for the given\n// storage account, caching it for future reuse.\nfunc (c *VFSContext) getAzureBlobClient(ctx context.Context, account string) (*azblob.Client, error) {\n\tif account == \"\" {\n\t\treturn nil, fmt.Errorf(\"Azure storage account is required\")\n\t}\n\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\n\tif client, ok := c.azureClients[account]; ok {\n\t\treturn client, nil\n\t}\n\n\tclient, err := newAzureClient(ctx, account)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif c.azureClients == nil {\n\t\tc.azureClients = make(map[string]*azblob.Client)\n\t}\n\tc.azureClients[account] = client\n\treturn client, nil","sourceCodeStart":583,"sourceCodeEnd":619,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/context.go#L583-L619","documentation":"getAzureBlobClient creates/caches azblob.Client instances per storage account. It refuses to proceed when the account string is empty, because an azblob client cannot be constructed without a target account. Normally unreachable directly, since buildAzureBlobPath validates the account first, but it is a defensive guard on the client-creation path.","triggerScenarios":"getClient dispatching to getAzureBlobClient with an empty account — possible only if a caller bypasses buildAzureBlobPath or passes an empty account string into the VFS Azure client factory.","commonSituations":"Programmatic use of the VFS Azure path/client APIs where the account argument is sourced from a config value that silently defaults to empty string.","solutions":["Ensure the account passed to the Azure Blob VFS path/client construction is non-empty before calling BuildVfsPath.","Route construction through BuildVfsPath so buildAzureBlobPath's URL validation populates the account correctly.","Check that the azureblob:// URL host (account) is populated, since it feeds getAzureBlobClient."],"exampleFix":"// before\nclient, err := ctx.getAzureBlobClient(ctx, account) // account == \"\"\n// after\nif account == \"\" { return fmt.Errorf(\"storage account must be set\") }\nclient, err := ctx.getAzureBlobClient(ctx, account)","handlingStrategy":"validation","validationCode":"if account == \"\" {\n    return errors.New(\"Azure storage account must be configured before building the VFS path\")\n}","typeGuard":"func accountConfigured(account string) bool { return account != \"\" }","tryCatchPattern":null,"preventionTips":["Always construct Azure VFS paths via BuildVfsPath so the URL is validated first.","Fail fast at config load time if the storage account value is empty.","Do not pass account strings straight from optional config fields without a default check."],"tags":["azure","vfs","configuration"],"backgroundTag":"azureblob-url-missing-storage-account","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"}