hashicorp/terraform · error
listing blobs
Error message
listing blobs: %v
What it means
Thrown by Workspaces() when client.ListBlobs(ctx, containerName, params) fails after the container client was successfully built. ListBlobs calls the Azure Blob REST List operation against the container to enumerate state files under the env: prefix. Fails on auth, container-not-found, network/firewall, or RBAC.
Solutions
- Verify container_name with `az storage container list --account-name <acct>`.
- With use_azuread_auth, grant Storage Blob Data Reader (list) / Data Contributor (read-write) to the identity.
- Check storage account Networking: allow your client IP or set AzureServices bypass.
- Reproduce with `az storage blob list -c <container> --account-name <acct> --auth-mode login` to isolate Terraform vs Azure.
- Confirm the container was not deleted; recreate if needed.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: confirm the container exists and the identity can list blobs.
func canListBlobs(ctx context.Context, acct, container string) error {
cmd := exec.CommandContext(ctx, "az", "storage", "blob", "list",
"--account-name", acct, "-c", container, "--auth-mode", "login", "--query", "[0].name", "-o", "tsv")
out, err := cmd.CombinedOutput()
if err != nil { return fmt.Errorf("cannot list blobs in %s/%s: %w (%s)", acct, container, err, out) }
return nil
} Prevention
- With AAD, grant Storage Blob Data Reader (list) / Data Contributor (read-write).
- Allow your client IP in the storage account firewall or enable AzureServices bypass.
- Smoke-test `az storage blob list` from the same identity before terraform workspace list.
- Use a config-lint rule to flag container names that don't match ^[a-z0-9]([a-z0-9-]{1,61}[a-z0-9])?$.
When it happens
Trigger: (a) container_name does not exist in the storage account. (b) Identity can authenticate but cannot list blobs (data-plane RBAC missing). (c) Storage account firewall / private endpoint blocks the request. (d) Container was deleted.
Common situations: Typo in container_name; storage account network firewall set to deny without your IP allowed; principal has Storage Account Contributor (control plane) but not Storage Blob Data Reader (data plane) when using AAD; container deleted out-of-band.
Related errors
- error snapshotting Blob
- new blob client
- new container client
- retrieving container client
- retrieving key for Storage Account
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/777c783df43bcba2.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/azure/backend_state.go:41
// reduce the chance of name conflicts with existing objects.
keyEnvPrefix = "env:"
)
func (b *Backend) Workspaces() ([]string, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
prefix := b.keyName + keyEnvPrefix
params := containers.ListBlobsInput{
Prefix: &prefix,
}
ctx := newCtx()
client, err := b.apiClient.getContainersClient(ctx)
if err != nil {
return nil, diags.Append(fmt.Errorf("retrieving container client: %v", err))
}
resp, err := client.ListBlobs(ctx, b.containerName, params)
if err != nil {
return nil, diags.Append(fmt.Errorf("listing blobs: %v", err))
}
envs := map[string]struct{}{}
for _, obj := range resp.Blobs.Blobs {
key := obj.Name
if strings.HasPrefix(key, prefix) {
name := strings.TrimPrefix(key, prefix)
// we store the state in a key, not a directory
if strings.Contains(name, "/") {
continue
}
envs[name] = struct{}{}
}
}
result := []string{backend.DefaultStateName}
for name := range envs {View on GitHub (pinned to d32a084675)