{"record":{"id":"ea3b54d8efca5246","repo":"opentofu/opentofu","slug":"error-listing-blobs-w","errorCode":null,"errorMessage":"error listing blobs: %w","messagePattern":"error listing blobs: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/azure/backend_state.go","lineNumber":155,"sourceCode":"}\n\nfunc getPaginatedResults(ctx context.Context, client azureClient, prefix string) ([]string, error) {\n\tcount := 1\n\tinitialMarker := \"\"\n\n\tparams := container.ListBlobsFlatOptions{\n\t\tPrefix: &prefix,\n\t\tMarker: &initialMarker,\n\t}\n\tresult := []string{backend.DefaultStateName}\n\tpager := client.NewListBlobsFlatPager(&params)\n\n\tfor pager.More() {\n\t\tlog.Printf(\"[TRACE] Getting page %d of blob results\", count)\n\n\t\tresp, err := pager.NextPage(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error listing blobs: %w\", err)\n\t\t}\n\n\t\tfor _, obj := range resp.Segment.BlobItems {\n\t\t\tkey := obj.Name\n\t\t\tif !strings.HasPrefix(*key, prefix) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tname := strings.TrimPrefix(*key, prefix)\n\t\t\t// we store the state in a key, not a directory\n\t\t\tif strings.Contains(name, \"/\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresult = append(result, name)\n\t\t}\n\n\t\tcount++\n\t}","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/opentofu/opentofu/blob/3561785c48c1ce615e7c50261bd351f26053efa2/internal/backend/remote-state/azure/backend_state.go#L137-L173","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the SAS token grants list on the container (srt=co and sp includes l) or use the account key","Confirm container_name exists and the credential has Storage Blob Data Reader/Contributor on it","Test with `az storage blob list --container-name <c> --account-name <a>` using the same credential","Check the network path/firewall and raise ARM_TIMEOUT_SECONDS if listing a huge container times out"],"exampleFix":"// before (SAS without list right)\nsas_token = \"sv=2022-11-02&ss=b&srt=o&sp=rw\"  # object-scoped, no list\n\n// after\nsas_token = \"sv=2022-11-02&ss=b&srt=co&sp=rl\"  # container-scoped with list","handlingStrategy":"validation","validationCode":"// pre-flight: prove the credential can list the container before running tofu\npager := containerClient.NewListBlobsFlatPager(&container.ListBlobsFlatOptions{Prefix: &prefix})\nif _, err := pager.NextPage(ctx); err != nil {\n    return fmt.Errorf(\"workspace enumeration will fail: %w\", err)\n}","typeGuard":"func isResponseError(err error, statusCode int) bool {\n    var re *azcore.ResponseError\n    return errors.As(err, &re) && re.StatusCode == statusCode\n}","tryCatchPattern":null,"preventionTips":["Generate SAS tokens with srt=co and sp including l, not object-scoped tokens","Grant AzureAD principals Storage Blob Data Contributor for state ownership","Keep container names stable; never delete the state container without migration","Add a pre-flight `az storage blob list` step in CI before tofu runs"],"tags":["azure","blob-storage","sas-token","permissions","workspaces","go"],"backgroundTag":null,"analyzedSha":"3561785c48c1ce615e7c50261bd351f26053efa2","analyzedAt":"2026-08-15T23:27:16.226Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}