opentofu/opentofu · error

error listing blobs: %w

Error message

error listing blobs: %w

What it means

Backend.Workspaces calls getPaginatedResults (internal/backend/remote-state/azure/backend_state.go:155) which pages through ListBlobsFlat under the prefix `<key>env:` to enumerate workspaces; any pager.NextPage failure is wrapped as 'error listing blobs'. This is the raw Azure List Blob container operation failing, not a name-filtering problem.

Source

Thrown at internal/backend/remote-state/azure/backend_state.go:155

}

func getPaginatedResults(ctx context.Context, client azureClient, prefix string) ([]string, error) {
	count := 1
	initialMarker := ""

	params := container.ListBlobsFlatOptions{
		Prefix: &prefix,
		Marker: &initialMarker,
	}
	result := []string{backend.DefaultStateName}
	pager := client.NewListBlobsFlatPager(&params)

	for pager.More() {
		log.Printf("[TRACE] Getting page %d of blob results", count)

		resp, err := pager.NextPage(ctx)
		if err != nil {
			return nil, fmt.Errorf("error listing blobs: %w", err)
		}

		for _, obj := range resp.Segment.BlobItems {
			key := obj.Name
			if !strings.HasPrefix(*key, prefix) {
				continue
			}

			name := strings.TrimPrefix(*key, prefix)
			// we store the state in a key, not a directory
			if strings.Contains(name, "/") {
				continue
			}
			result = append(result, name)
		}

		count++
	}

View on GitHub (pinned to 3561785c48)

Solutions

  1. Verify the SAS token grants list on the container (srt=co and sp includes l) or use the account key
  2. Confirm container_name exists and the credential has Storage Blob Data Reader/Contributor on it
  3. Test with `az storage blob list --container-name <c> --account-name <a>` using the same credential
  4. Check the network path/firewall and raise ARM_TIMEOUT_SECONDS if listing a huge container times out

Example fix

// before (SAS without list right)
sas_token = "sv=2022-11-02&ss=b&srt=o&sp=rw"  # object-scoped, no list

// after
sas_token = "sv=2022-11-02&ss=b&srt=co&sp=rl"  # container-scoped with list
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight: prove the credential can list the container before running tofu
pager := containerClient.NewListBlobsFlatPager(&container.ListBlobsFlatOptions{Prefix: &prefix})
if _, err := pager.NextPage(ctx); err != nil {
    return fmt.Errorf("workspace enumeration will fail: %w", err)
}

Type guard

func isResponseError(err error, statusCode int) bool {
    var re *azcore.ResponseError
    return errors.As(err, &re) && re.StatusCode == statusCode
}

Prevention

When it happens

Trigger: SAS token missing the list permission (sp without l) or not signed for containers (srt without co); 403 from an AzureAD credential lacking Storage Blob Data Reader; wrong or deleted container_name; storage firewall blocking the client; context timeout (ARM_TIMEOUT_SECONDS) while paging a very large container.

Common situations: Minimal SAS tokens generated with read/write only, breaking `tofu workspace list`; permissions tightened after a security review; the state container was deleted or renamed; the AzureAD principal lost its role assignment.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/ea3b54d8efca5246. Report an issue: GitHub.