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
- Verify the path exists and is readable by the terraform process: 'cat <path>' or 'test -r <path>'.
- Use an absolute path for 'credentials' to avoid working-directory issues.
- 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.
- 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
- Use an absolute path for 'credentials'.
- Confirm the file is readable by the terraform process ('test -r <path>').
- Update paths after key rotation.
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
- the string provided in credentials is neither valid json nor
- can't set both encryption_key and kms_encryption_key
- storage.NewClient() failed: %v
- unable to initialize the location client: %#v
- sasToken cannot be empty
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/404bb1d757d14bc2.
Report an issue: GitHub.