hashicorp/terraform · error
Unable to list objects in S3 bucket
Error message
Unable to list objects in S3 bucket %q with prefix %q: %w
What it means
Thrown by Backend.Workspaces in the S3 backend when ListObjectsV2 NextPage errors and the error is neither NoSuchBucket nor (in the default-prefix case) an AccessDenied smithy.APIError. It is the catch-all list failure wrapping the underlying error with %w so callers can errors.Is/As it. The state listing operation cannot proceed.
Solutions
- Inspect the wrapped error (%w) for `SlowDown`/`Throttling` and retry with backoff.
- Grant the principal `s3:ListBucket` on the bucket scoped to the workspace key prefix.
- Refresh STS credentials (re-assume role) if the session expired.
- Verify KMS key used for bucket is enabled and accessible.
Defensive patterns
Strategy: retry
Validate before calling
// preflight: assert ListBucket permission with a scoped call
_, err := s3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{Bucket: aws.String(b), MaxKeys: aws.Int32(1)})
if err != nil { return fmt.Errorf("cannot list bucket %s: %w", b, err) } Type guard
func isAccessDeniedOrThrottle(err error) bool {
var ae smithy.APIError
if errors.As(err, &ae) {
return ae.ErrorCode()=="AccessDenied" || ae.ErrorCode()=="SlowDown" || ae.ErrorCode()=="Throttling"
}
return false
} Try / catch
page, err := pages.NextPage(ctx)
if err != nil {
var ae smithy.APIError
if errors.As(err, &ae) && (ae.ErrorCode()=="SlowDown"||ae.ErrorCode()=="Throttling") { backoff(); continue }
return err
} Prevention
- Grant s3:ListBucket scoped to the workspace key prefix.
- Refresh STS credentials before long lists.
- Add request-exponential-backoff for S3 list throttling.
When it happens
Trigger: pages.NextPage(ctx) errors, IsA[*s3types.NoSuchBucket] is false, and either the prefix is non-default or the error is not a smithy AccessDenied. Causes: throttling (SlowDown), transient 5xx, iam ListBucket permission missing, KMS decrypt issue on listing, or STS token expired mid-list.
Common situations: Throttling on a hot bucket; expired STS session token; custom workspace_key_prefix with s3:ListBucket scoped to a different prefix; KMS key disabled; region partition mismatch.
Related errors
- Unable to access object
- can't delete default state
- Error unlocking S3 state. Lock ID
- failed to lock s3 state
- failed to upload state
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/5da3802fa9f74593.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/s3/backend_state.go:78
}
wss := []string{backend.DefaultStateName}
ctx, baselog := baselogging.NewHcLogger(ctx, log)
ctx = baselogging.RegisterLogger(ctx, baselog)
pages := s3.NewListObjectsV2Paginator(b.s3Client, params)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)
if err != nil {
if IsA[*s3types.NoSuchBucket](err) {
return nil, diags.Append(fmt.Errorf(errS3NoSuchBucket, b.bucketName, err))
}
if foo, ok := As[smithy.APIError](err); b.workspaceKeyPrefix == defaultWorkspaceKeyPrefix && ok && foo.ErrorCode() == "AccessDenied" {
log.Warn("Unable to list non-default workspaces", "err", err.Error())
return wss[:1], nil
}
return nil, diags.Append(fmt.Errorf("Unable to list objects in S3 bucket %q with prefix %q: %w", b.bucketName, prefix, err))
}
for _, obj := range page.Contents {
ws := b.keyEnv(aws.ToString(obj.Key))
if ws != "" {
wss = append(wss, ws)
}
}
}
sort.Strings(wss[1:])
return wss, diags
}
func (b *Backend) keyEnv(key string) string {
prefix := b.workspaceKeyPrefix
if prefix == "" {View on GitHub (pinned to d32a084675)