hashicorp/terraform · error

Error loading credentials: %s

Error message

Error loading credentials: %s

What it means

Raised by the GCS backend when readPathOrContents(creds) fails — i.e. the 'credentials' value looked like a file path but the file could not be opened or read. The backend accepts credentials either as an inline JSON blob or as a path to a JSON key file; this error specifically means a path was attempted and the read failed. The wrapped %s is the underlying os/io error.

Source

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

			AccessToken: v,
		})
	} else if v := data.String("credentials"); v != "" {
		creds = v
	} else if v := os.Getenv("GOOGLE_BACKEND_CREDENTIALS"); v != "" {
		creds = v
	} else {
		creds = os.Getenv("GOOGLE_CREDENTIALS")
	}

	if tokenSource != nil {
		credOptions = append(credOptions, option.WithTokenSource(tokenSource))
	} else if creds != "" {

		// to mirror how the provider works, we accept the file path or the contents
		contents, err := readPathOrContents(creds)
		if err != nil {
			return backendbase.ErrorAsDiagnostics(
				fmt.Errorf("Error loading credentials: %s", err),
			)
		}

		if !json.Valid([]byte(contents)) {
			return backendbase.ErrorAsDiagnostics(
				fmt.Errorf("the string provided in credentials is neither valid json nor a valid file path"),
			)
		}

		credOptions = append(credOptions, option.WithCredentialsJSON([]byte(contents)))
	}

	// Service Account Impersonation
	if v := data.String("impersonate_service_account"); v != "" {
		ServiceAccount := v
		var delegates []string

		delegatesVal := data.GetAttr("impersonate_service_account_delegates", cty.List(cty.String))

View on GitHub (pinned to c9def3e214)

Solutions

  1. Verify the path exists and is readable by the terraform process: 'cat <path>' or 'test -r <path>'.
  2. Use an absolute path for 'credentials' to avoid working-directory issues.
  3. If you meant to inline the JSON, ensure the value is valid JSON (then error 219 would not apply) — do not paste a path that does not resolve.
  4. After key rotation, update the path/env var to the new key file.

Example fix

# before: relative path that fails from another cwd
credentials = "./keys/sa.json"
# after: absolute path
credentials = "/home/user/project/keys/sa.json"
# verify
test -r /home/user/project/keys/sa.json && echo ok
Defensive patterns

Strategy: validation

Validate before calling

// Validate the credentials path before init.
func validateCredsPath(creds string) error {
    // if it doesn't parse as JSON, it must be a readable file
    if json.Valid([]byte(creds)) { return nil }
    info, err := os.Stat(creds)
    if err != nil { return fmt.Errorf("credentials path %q: %w", creds, err) }
    if info.IsDir() { return fmt.Errorf("credentials path is a directory: %q", creds) }
    return nil
}

Prevention

When it happens

Trigger: At backend.go:195-199: readPathOrContents returns an error. Triggered when 'credentials' (or GOOGLE_BACKEND_CREDENTIALS / GOOGLE_CREDENTIALS) is a string that is not pure JSON, so readPathOrContents treats it as a path, but the path does not exist or is unreadable.

Common situations: credentials path is relative and terraform runs from a different working directory; the key file was deleted/renamed; path has a typo; file permissions deny the terraform process; GOOGLE_CREDENTIALS points to a stale path after key rotation.

Related errors


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