{"record":{"id":"5da3802fa9f74593","repo":"hashicorp/terraform","slug":"unable-to-list-objects-in-s3-bucket-q-with-prefix","errorCode":null,"errorMessage":"Unable to list objects in S3 bucket %q with prefix %q: %w","messagePattern":"Unable to list objects in S3 bucket %q with prefix %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/s3/backend_state.go","lineNumber":78,"sourceCode":"\t}\n\n\twss := []string{backend.DefaultStateName}\n\n\tctx, baselog := baselogging.NewHcLogger(ctx, log)\n\tctx = baselogging.RegisterLogger(ctx, baselog)\n\n\tpages := s3.NewListObjectsV2Paginator(b.s3Client, params)\n\tfor pages.HasMorePages() {\n\t\tpage, err := pages.NextPage(ctx)\n\t\tif err != nil {\n\t\t\tif IsA[*s3types.NoSuchBucket](err) {\n\t\t\t\treturn nil, diags.Append(fmt.Errorf(errS3NoSuchBucket, b.bucketName, err))\n\t\t\t}\n\t\t\tif foo, ok := As[smithy.APIError](err); b.workspaceKeyPrefix == defaultWorkspaceKeyPrefix && ok && foo.ErrorCode() == \"AccessDenied\" {\n\t\t\t\tlog.Warn(\"Unable to list non-default workspaces\", \"err\", err.Error())\n\t\t\t\treturn wss[:1], nil\n\t\t\t}\n\t\t\treturn nil, diags.Append(fmt.Errorf(\"Unable to list objects in S3 bucket %q with prefix %q: %w\", b.bucketName, prefix, err))\n\t\t}\n\n\t\tfor _, obj := range page.Contents {\n\t\t\tws := b.keyEnv(aws.ToString(obj.Key))\n\t\t\tif ws != \"\" {\n\t\t\t\twss = append(wss, ws)\n\t\t\t}\n\t\t}\n\t}\n\n\tsort.Strings(wss[1:])\n\treturn wss, diags\n}\n\nfunc (b *Backend) keyEnv(key string) string {\n\tprefix := b.workspaceKeyPrefix\n\n\tif prefix == \"\" {","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/s3/backend_state.go#L60-L96","documentation":"Thrown in Backend.Workspaces (s3/backend_state.go:78) for a ListObjectsV2 failure that is neither NoSuchBucket nor the legacy defaultWorkspaceKeyPrefix (\"env:\") AccessDenied special case. The underlying AWS SDK error is wrapped with %w so its code (e.g. AccessDenied, SlowDown) is reachable programmatically.","triggerScenarios":"IAM principal lacks s3:ListBucket on the bucket/prefix (when using a non-legacy workspaceKeyPrefix); S3 throttling (SlowDown); STS/credentials expired mid-call; network error; a bucket policy explicitly denying ListBucket.","commonSituations":"Least-privilege IAM role scoped to a custom prefix but Terraform lists the whole bucket; switched workspaceKeyPrefix without updating the policy; throttled by a burst of automation; expired assumed-role credentials.","solutions":["Grant s3:ListBucket on arn:aws:s3:::<bucket> scoped to the workspace prefix resource.","If using the legacy env: prefix, ensure the policy allows listing that prefix (the code only silently downgrades AccessDenied for env:).","Retry on SlowDown/throttling with backoff.","Refresh expired STS credentials and re-run."],"exampleFix":"// before: IAM only allows s3:GetObject/PutObject\n\n// after: also allow listing the workspace prefix\n// {\n//   \"Effect\": \"Allow\",\n//   \"Action\": [\"s3:ListBucket\"],\n//   \"Resource\": \"arn:aws:s3:::mycorp-tfstate\",\n//   \"Condition\": {\"StringLike\": {\"s3:prefix\": [\"env:/*\", \"\"]}}\n// }","handlingStrategy":"validation","validationCode":"// Pre-check list permission with an explicit ListObjectsV2 call\n// _, err := s3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{\n//   Bucket: aws.String(bucket), Prefix: aws.String(prefix), MaxKeys: aws.Int32(1),\n// })\n// if err != nil { /* surface IAM/policy gap before init */ }","typeGuard":"// Narrow the wrapped smithy API error to react by code\n// var apiErr smithy.APIError\n// if errors.As(err, &apiErr) {\n//   switch apiErr.ErrorCode() {\n//   case \"AccessDenied\": /* IAM policy */\n//   case \"SlowDown\":     /* retry */\n//   }\n// }","tryCatchPattern":"// Retry throttling; surface permission errors distinctly\n// var apiErr smithy.APIError\n// if errors.As(err, &apiErr) && apiErr.ErrorCode()==\"SlowDown\" { /* backoff retry */ } else { return err }","preventionTips":["Scope s3:ListBucket to the workspace prefix your automation actually uses.","If you rely on the legacy env: prefix, keep it in the policy.","Refresh STS credentials with margin before long runs."],"tags":["s3","aws","permissions","iam","list"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}