hashicorp/terraform · error
listing blobs: %v
Error message
listing blobs: %v
What it means
A wrapper error from Backend.Workspaces (backend_state.go:39-41). After the containers client is built, the backend calls client.ListBlobs against the storage container to enumerate workspace state files; if that data-plane call fails, this error is returned. Unlike error 148 this is a real network/auth failure against the storage data plane, not a client-construction problem.
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 c9def3e214)
Solutions
- Confirm container_name matches an existing container: az storage container list --account-name <account> --auth-mode login
- Grant the principal 'Storage Blob Data Contributor' for data-plane access (RBAC) or widen the SAS token permissions
- Check storage account network firewall allows your client IP / VNet
- If using a SAS token, confirm it has not expired and includes List ('l') permission
Example fix
# before: storage firewall blocks the runner az storage account update -n mystage --default-action Deny # after: allow the runner's IP (or enable the managed identity / VNet rule) az storage account update -n mystage --default-action Deny \ --bypass AzureServices az storage account network-rule add -n mystage --ip-address 203.0.113.10
Defensive patterns
Strategy: retry
Validate before calling
# Pre-flight: list blobs to confirm data-plane access and container name
az storage blob list --account-name "$ARM_STORAGE_ACCOUNT_NAME" -c "$ARM_CONTAINER_NAME" --prefix "${ARM_KEY}env:" --auth-mode login >/dev/null 2>&1 \
&& echo "OK: can list workspace blobs" || echo "WARN: listing failed -> error 149 possible (container name / firewall / permissions)" Try / catch
# Bash: retry transient data-plane listing with backoff
list_workspace_blobs() {
for attempt in 1 2 3 4 5; do
if terraform workspace list; then return 0; fi
sleep $((attempt * attempt))
done
echo "workspace list failed after retries; check storage firewall/permissions"
return 1
} Prevention
- Grant 'Storage Blob Data Contributor' (data-plane) or a SAS with list permission
- Allowlist your runner IP / VNet in the storage account network firewall
- Use --auth-mode login (AAD) in CI to avoid expiring SAS tokens
When it happens
Trigger: Produced at backend_state.go:39-41 during workspace enumeration when client.ListBlobs(ctx, b.containerName, params) returns an error. The prefix used is '<keyName>env:'.
Common situations: Wrong container_name; the credential lacks 'Container/blob/list' data-plane permission; the container was deleted; network/firewall blocking the storage endpoint (storage account firewall set to selected networks); a SAS token that expired.
Related errors
- retrieving container client: %v
- listing Keys for %s: %+v
- Too many command line arguments. Did you mean to use -chdir?
- retrieving %s: %+v
- retrieving key for Storage Account %q: %s
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/777c783df43bcba2.
Report an issue: GitHub.