This error occurs when Terraform cannot locate authentication credentials for Terraform Cloud (app.terraform.io). The token must be configured in your CLI config file, environment variables, or interactive login to access remote backends and registries.
Terraform Cloud requires authentication for remote state storage, module registries, and policy enforcement. When Terraform tries to connect to app.terraform.io or other Terraform Cloud services, it looks for an API token in three places: your .terraform.d/credentials.tfrc.json file, the TFE_TOKEN environment variable, or interactive login. If none of these sources provide a valid token, Terraform fails with this error. The error message is often cryptic because it doesn't indicate which authentication method failed or why—you must check all three sources to identify the root cause.
Visit Terraform Cloud (https://app.terraform.io), sign in, and create a new API token:
1. Click your profile icon (top right) → Account settings
2. Navigate to "Tokens"
3. Click "Create an API token"
4. Give it a descriptive name (e.g., "Local dev" or "CI/CD")
5. Choose appropriate scope (usually "Full access")
6. Click "Generate token"
7. Copy the token immediately — it is only displayed once
Save the token to a text editor temporarily. Do not lose it; you'll need it in the next steps.
The simplest method for local development is the terraform login command:
terraform loginTerraform will:
1. Prompt: "Do you want to copy these credentials to the local credentials file? (yes/no)"
2. Open a browser to app.terraform.io to create a token (if not already done)
3. Ask you to paste the token back into the terminal
4. Automatically save credentials to ~/.terraform.d/credentials.tfrc.json
After this, terraform init and other commands should work. Verify:
terraform initIf terraform login is unavailable or non-interactive (common in CI/CD), manually create the credentials file:
mkdir -p ~/.terraform.dCreate ~/.terraform.d/credentials.tfrc.json:
{
"credentials": {
"app.terraform.io": {
"token": "YOUR_API_TOKEN_HERE"
}
}
}Replace YOUR_API_TOKEN_HERE with your actual Terraform Cloud API token (from step 1).
Set proper permissions:
chmod 600 ~/.terraform.d/credentials.tfrc.jsonVerify the file was created and is readable:
ls -la ~/.terraform.d/credentials.tfrc.jsonIn automated environments (GitHub Actions, GitLab CI, Jenkins), use the TF_TOKEN_app_terraform_io environment variable instead of file-based credentials:
GitHub Actions example:
jobs:
terraform:
runs-on: ubuntu-latest
env:
TF_TOKEN_app_terraform_io: ${{ secrets.TERRAFORM_API_TOKEN }}
steps:
- uses: actions/checkout@v3
- uses: hashicorp/setup-terraform@v2
- run: terraform init
- run: terraform planGitLab CI example:
terraform-plan:
image: hashicorp/terraform:latest
variables:
TF_TOKEN_app_terraform_io: $TERRAFORM_API_TOKEN
script:
- terraform init
- terraform planThe TF_TOKEN_ prefix combined with hostname (app.terraform.io becomes app_terraform_io) tells Terraform where to use this token. Store the actual token value in your CI/CD platform's secrets management, not in code.
If you installed Terraform via snap, it may look for credentials in the wrong location:
mkdir -p ~/.terraform.d
ln -s ~/.terraformrc ~/.terraform.d/credentials.tfrc.jsonIf you haven't created ~/.terraformrc yet, first generate it with terraform login, then create the symlink above. Verify the symlink:
ls -la ~/.terraform.d/You should see:
lrwxrwxrwx credentials.tfrc.json -> ~/.terraformrcTest that Terraform can now authenticate:
terraform version # Should not error if credentials are validIf using a self-hosted Terraform Enterprise or custom backend server (not app.terraform.io), add credentials for that hostname:
{
"credentials": {
"app.terraform.io": {
"token": "YOUR_CLOUD_TOKEN"
},
"terraform.example.com": {
"token": "YOUR_ENTERPRISE_TOKEN"
}
}
}Or via environment variable (replace hostname with underscores):
export TF_TOKEN_terraform_example_com="YOUR_ENTERPRISE_TOKEN"Then configure your backend block:
terraform {
cloud {
hostname = "terraform.example.com"
organization = "my-org"
}
}Verify connectivity:
terraform initTerraform token management has evolved. Older documentation mentions TFE_TOKEN, but the recommended modern pattern is TF_TOKEN_{hostname} where the hostname replaces dots with underscores. Both work, but TF_TOKEN_* is more explicit and supports multiple backends.
Token scope and permissions: User tokens have "Full access" by default. Organization tokens and team tokens have more restricted scopes. If you're seeing "insufficient permissions" errors after fixing the "token not found" error, you may need a user token rather than an organization token.
Snap and containerized Terraform: Snap sandboxing and container isolation can cause credential file visibility issues. If running terraform in Docker, mount ~/.terraform.d as a volume or pass credentials via environment variables. For snap, the snap confinement model may prevent access to your home directory entirely—consider installing via apt or Homebrew instead.
Terraform Cloud organization management: If you have multiple Terraform Cloud organizations, each with different tokens, you'll need separate credentials entries for each, or use organization-specific environment variables at the CI/CD level. Team workflows often require a dedicated service account token rather than personal user tokens.
Error: Error installing helm release: cannot re-use a name that is still in use
How to fix "release name in use" error in Terraform with Helm
Error: Error creating GKE Cluster: BadRequest
BadRequest error creating GKE cluster in Terraform
Error: External program failed to produce valid JSON
External program failed to produce valid JSON
Error: Unsupported argument in child module call
How to fix "Unsupported argument in child module call" in Terraform
Error: network is unreachable
How to fix "network is unreachable" in Terraform