hashicorp/terraform · critical

storage.NewClient() failed: %v

Error message

storage.NewClient() failed: %v

What it means

Wraps the error returned by cloud.google.com/go/storage.NewClient during backend Configure(). NewClient builds the underlying HTTP transport and resolves the token source (credentials JSON, access token, impersonated token, or Application Default Credentials); any failure there is surfaced verbatim in the %v slot. This is the catch-all for auth, transport, and endpoint construction problems before any object request is made.

Source

Thrown at internal/backend/remote-state/gcs/backend.go:256

		}

		opts = append(opts, option.WithTokenSource(ts))

	} else {
		opts = append(opts, credOptions...)
	}

	opts = append(opts, option.WithUserAgent(httpclient.UserAgentString()))

	// Custom endpoint for storage API
	if storageEndpoint := data.String("storage_custom_endpoint"); storageEndpoint != "" {
		endpoint := option.WithEndpoint(storageEndpoint)
		opts = append(opts, endpoint)
	}
	client, err := storage.NewClient(ctx, opts...)
	if err != nil {
		return backendbase.ErrorAsDiagnostics(
			fmt.Errorf("storage.NewClient() failed: %v", err),
		)
	}

	b.storageClient = client

	// Customer-supplied encryption
	key := data.String("encryption_key")
	if key != "" {
		kc, err := readPathOrContents(key)
		if err != nil {
			return backendbase.ErrorAsDiagnostics(
				fmt.Errorf("Error loading encryption key: %s", err),
			)
		}

		// The GCS client expects a customer supplied encryption key to be
		// passed in as a 32 byte long byte slice. The byte slice is base64
		// encoded before being passed to the API. We take a base64 encoded key

View on GitHub (pinned to c9def3e214)

Solutions

  1. Run 'gcloud auth application-default login' (or set GOOGLE_APPLICATION_CREDENTIALS / GOOGLE_CREDENTIALS to a valid key file) and retry 'terraform init'.
  2. If using impersonation, grant the calling identity 'roles/iam.serviceAccountTokenCreator' on the target SA; verify with 'gcloud iam service-accounts get-access-token'.
  3. Inspect the %v detail: a 401/403 means credentials/scopes, a dial error means network/endpoint; fix the matching cause.
  4. If storage_custom_endpoint is set, confirm the URL is reachable and returns the Storage JSON API shape.

Example fix

// before (env)
GOOGLE_CREDENTIALS=$(cat /etc/secrets/key.json)   # key was rotated

// after
export GOOGLE_APPLICATION_CREDENTIALS=/etc/secrets/current-key.json
gcloud auth application-default-login   # or WIF for CI
terraform init
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight credential check before terraform init
import "cloud.google.com/go/storage"
func canCreateStorageClient(ctx context.Context) error {
    c, err := storage.NewClient(ctx)
    if err != nil { return err }
    c.Close()
    return nil
}

Try / catch

if diags := backend.Configure(configVal); diags.HasErrors() {
    for _, d := range diags {
        if strings.Contains(d.Description().Summary, "storage.NewClient() failed") {
            // surface auth/network remediation hints, attempt ADC refresh, or abort
        }
    }
}

Prevention

When it happens

Trigger: Configure() reaches storage.NewClient with: invalid/revoked credentials JSON, an expired access_token, an impersonate_service_account that the caller lacks 'iam.serviceAccounts.generateAccessToken' on, GOOGLE_APPLICATION_CREDENTIALS pointing at a missing file, no network, or an unreachable storage_custom_endpoint.

Common situations: CI runners without GCP workload identity / ADC set up; a service-account JSON key that was rotated; impersonation target without the Service Account Token Creator role; air-gapped environment; GOOGLE_STORAGE_CUSTOM_ENDPOINT typo'd to a host that refuses connections.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/f0327ea735258656. Report an issue: GitHub.