hashicorp/terraform · error
can't locate credentials file: %s
Error message
can't locate credentials file: %s
What it means
Emitted by `Config.CredentialsSource` (credentials.go:45) when `CredentialsConfigFile()` (which calls `ConfigDir()` then `filepath.Join`) returns an error — i.e. the user's config/home directory cannot be determined. The comment at credentials.go:43-44 notes this is very unlikely because a successfully loaded `Config` implies the dir was already found.
Source
Thrown at internal/command/cliconfig/credentials.go:45
// that the credentials source will use when asked to save or forget credentials
// and when a "credentials helper" program is not active.
func CredentialsConfigFile() (string, error) {
configDir, err := ConfigDir()
if err != nil {
return "", err
}
return filepath.Join(configDir, "credentials.tfrc.json"), nil
}
// CredentialsSource creates and returns a service credentials source whose
// behavior depends on which "credentials" and "credentials_helper" blocks,
// if any, are present in the receiving config.
func (c *Config) CredentialsSource(helperPlugins pluginDiscovery.PluginMetaSet) (*CredentialsSource, error) {
credentialsFilePath, err := CredentialsConfigFile()
if err != nil {
// If we managed to load a Config object at all then we would already
// have located this file, so this error is very unlikely.
return nil, fmt.Errorf("can't locate credentials file: %s", err)
}
var helper svcauth.CredentialsSource
var helperType string
for givenType, givenConfig := range c.CredentialsHelpers {
available := helperPlugins.WithName(givenType)
if available.Count() == 0 {
log.Printf("[ERROR] Unable to find credentials helper %q; ignoring", givenType)
break
}
selected := available.Newest()
helperSource := svcauth.HelperProgramCredentialsSource(selected.Path, givenConfig.Args...)
helper = svcauth.CachingCredentialsSource(helperSource) // cached because external operation may be slow/expensive
helperType = givenType
// There should only be zero or one "credentials_helper" blocks. WeView on GitHub (pinned to c9def3e214)
Solutions
- Ensure `HOME` (Unix) or `APPDATA`/`USERPROFILE` (Windows) is set to a writable directory.
- Set `TF_CLI_CONFIG_FILE` to an explicit config path so `ConfigDir()` is bypassed where possible.
- Run Terraform as a user with a resolvable home directory.
Example fix
# before (container without HOME) terraform login # can't locate credentials file: $HOME is not defined # after export HOME=/tmp/tfhome mkdir -p "$HOME/.terraform.d" terraform login
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify a config/home dir is resolvable before login/apply.
func homeResolvable() error {
if dir, err := cliconfig.ConfigDir(); err != nil {
return fmt.Errorf("no config/home dir: %w; set HOME or TF_CLI_CONFIG_FILE", err)
} else {
return os.MkdirAll(dir, 0o755)
}
} Try / catch
// src, err := cfg.CredentialsSource(plugins)
if err != nil {
if strings.Contains(err.Error(), "can't locate credentials file") {
// fix HOME / TF_CLI_CONFIG_FILE and retry
}
return err
} Prevention
- Always set `HOME` (or `APPDATA` on Windows) for Terraform processes.
- Use `TF_CLI_CONFIG_FILE` to pin an explicit config path in containers.
- Run Terraform under a user with a real home directory.
When it happens
Trigger: Calling `CredentialsSource(...)` when `ConfigDir()` fails: `$HOME` is unset on Unix, `%APPDATA%` unavailable on Windows, or the home-dir resolver returns an error.
Common situations: Running Terraform under a service account/container without `HOME` set; hardened environments that strip home-dir env vars; running embedded Terraform internals from a context with no user profile.
Related errors
- The credentials %q block has an invalid hostname: %s
- unable to determine credentials file path: %s
- unable to build authorizer for Storage API: %+v
- unable to build authorizer for Resource Manager API: %+v
- building Storage Accounts client: %+v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/83f146b3a6f5692d.
Report an issue: GitHub.