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

  1. Confirm container_name matches an existing container: az storage container list --account-name <account> --auth-mode login
  2. Grant the principal 'Storage Blob Data Contributor' for data-plane access (RBAC) or widen the SAS token permissions
  3. Check storage account network firewall allows your client IP / VNet
  4. 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

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


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/777c783df43bcba2. Report an issue: GitHub.