hashicorp/terraform · error
querying Cloud Storage failed: %v
Error message
querying Cloud Storage failed: %v
What it means
Workspaces() lists state files in the bucket by calling bucket.Objects(...).Next() in a loop; any non-iterator.Done error from the GCS list API is surfaced here. This is the first network/object call after NewClient, so it commonly reflects bucket-existence or IAM issues rather than auth (auth would already have failed in NewClient).
Source
Thrown at internal/backend/remote-state/gcs/backend_state.go:47
// state is always returned as the first element in the slice.
func (b *Backend) Workspaces() ([]string, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
ctx := context.TODO()
states := []string{backend.DefaultStateName}
bucket := b.storageClient.Bucket(b.bucketName)
objs := bucket.Objects(ctx, &storage.Query{
Delimiter: "/",
Prefix: b.prefix,
})
for {
attrs, err := objs.Next()
if err == iterator.Done {
break
}
if err != nil {
return nil, diags.Append(fmt.Errorf("querying Cloud Storage failed: %v", err))
}
name := path.Base(attrs.Name)
if !strings.HasSuffix(name, stateFileSuffix) {
continue
}
st := strings.TrimSuffix(name, stateFileSuffix)
if st != backend.DefaultStateName {
states = append(states, st)
}
}
sort.Strings(states[1:])
return states, diags
}
// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.View on GitHub (pinned to c9def3e214)
Solutions
- Confirm the bucket exists: 'gsutil ls gs://<bucket>' and matches backend.bucket.
- Grant the SA 'roles/storage.objectAdmin' (read+list+write) or at minimum 'roles/storage.objectViewer' plus objectViewer on the prefix.
- If the %v says 'notFound', fix the bucket name; if 'forbidden', fix IAM; if transient, retry 'terraform workspace list'.
- Confirm prefix doesn't escape into a bucket the SA lacks access to.
Example fix
// before: bucket typo bucket = "myco-terraform-state-prod" // after bucket = "myco-tfstate-prod" # actual bucket gsutil iam ch serviceAccount:tf-deployer@proj.iam.gserviceaccount.com:roles/storage.objectAdmin gs://myco-tfstate-prod
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: confirm bucket is listable
import "cloud.google.com/go/storage"
func bucketListable(ctx context.Context, c *storage.Client, bucket string) error {
it := c.Bucket(bucket).Objects(ctx, nil)
if _, err := it.Next(); err != nil && err != iterator.Done { return err }
return nil
} Try / catch
var states []string
for attempt := 0; attempt < 3; attempt++ {
var diags tfdiags.Diagnostics
states, diags = backend.Workspaces()
if !diags.HasErrors() { break }
if !isTransientGCS(diags) { break }
time.Sleep(backoff(attempt))
} Prevention
- Grant the SA 'roles/storage.objectAdmin' or 'roles/storage.objectViewer' on the bucket.
- Validate the bucket name with 'gsutil ls' in a pre-flight CI step.
- Use distinct prefixes per project to avoid IAM scope creep.
When it happens
Trigger: 'terraform workspace list' (or any command that enumerates workspaces) against a bucket the caller can't storage.objects.list, a bucket name that doesn't exist, an invalid prefix, or transient GCS API errors.
Common situations: Wrong bucket name in backend config; new SA without 'roles/storage.objectViewer' / 'roles/storage.objectAdmin'; cross-project bucket without granted access; transient 5xx from GCS.
Related errors
- storage.NewClient() failed: %v
- cowardly refusing to delete the %q state
- %q is not a valid state name
- Failed to open state file at %v: %v
- Failed to read state file from %v: %v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/05eb8275bcf50e37.
Report an issue: GitHub.