Terraform Error: '401 Unauthorized' from the Remote/Cloud Backend
Fix Terraform's remote/cloud backend '401 Unauthorized' error: diagnose invalid API tokens, missing credentials blocks, wrong hostname, and TF_TOKEN environment variables.
- #terraform
- #iac
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Exact Error Message
╷
│ Error: Failed to get existing workspaces: unauthorized
│
│ Terraform failed to fetch workspaces from the backend. The error was: 401 Unauthorized.
│ Please check your API token and try again.
╵
With HCP Terraform / Terraform Enterprise you may instead see:
╷
│ Error: Required token could not be found
│
│ Run "terraform login" to obtain and save credentials for the host, or set the
│ TF_TOKEN_app_terraform_io environment variable.
╵
What It Means
Terraform’s remote and cloud backends talk to HCP Terraform (formerly Terraform Cloud), Terraform Enterprise, or another API-driven state host over HTTPS. Every request carries a bearer token. A 401 Unauthorized means the backend received your request but rejected the credential: the token is missing, malformed, expired, revoked, or scoped to a different organization than the one your configuration targets.
This is an authentication failure, not a network or configuration-syntax failure. Terraform reached the host successfully — the host simply refused to authorize the operation. It surfaces most often on terraform init, on the first plan, or right after a token was rotated.
Common Causes
- No token is stored for the host and no
TF_TOKEN_*environment variable is set. - The stored credential in
~/.terraform.d/credentials.tfrc.jsonis stale after a token rotation or aterraform logout. - A user/team API token was revoked, or a team token lost access to the target organization.
- The
hostnamein thecloud/remoteblock does not match the host the token was issued for (for exampleapp.terraform.iovs a private Terraform Enterprise domain). - In CI, the
TF_TOKEN_app_terraform_iovariable is unset, truncated, or contains stray whitespace/quotes. - The token belongs to a different organization than the one named in the backend block.
Diagnostic Commands
Confirm which host and organization your configuration targets:
terraform version
grep -R "cloud\|backend\|organization\|hostname" *.tf
Check whether a credential is actually stored for the host:
cat ~/.terraform.d/credentials.tfrc.json
Verify the token directly against the API (a valid token returns 200 and your account JSON; a bad one returns 401):
curl -sS -o /dev/null -w "%{http_code}\n" \
--header "Authorization: Bearer $TF_TOKEN_app_terraform_io" \
https://app.terraform.io/api/v2/account/details
Re-run init with debug logging to see exactly which host is challenged:
TF_LOG=DEBUG terraform init 2>&1 | grep -iE "unauthorized|token|host"
Step-by-Step Resolution
- Identify the exact hostname. Open your backend configuration and note the
hostname(defaults toapp.terraform.iofor thecloudblock):
terraform {
cloud {
organization = "my-org"
hostname = "app.terraform.io"
workspaces {
name = "production"
}
}
}
- Obtain and store a fresh token interactively. This writes
credentials.tfrc.jsonfor you:
terraform login app.terraform.io
- For CI or non-interactive runs, export a token as an environment variable instead. The variable name is the hostname with dots replaced by underscores:
export TF_TOKEN_app_terraform_io="$(cat /run/secrets/tfe_token)"
terraform init
-
If the token is correct but still rejected, confirm it has access to the organization named in the block. Generate a new team or organization token scoped to that org from the HCP Terraform UI (Settings → Teams/Tokens), then repeat step 3.
-
Clear any stale credential that might shadow the new one, then re-init:
terraform logout app.terraform.io
terraform login app.terraform.io
terraform init -reconfigure
- Confirm success —
initshould now list workspaces without a 401:
Initializing HCP Terraform...
Terraform Cloud has been successfully initialized!
If you are automating token setup and secret plumbing across many pipelines, the Terraform CI credentials prompts in the prompt library can generate the environment-variable and secrets wiring for your specific CI platform.
Prevention
- Prefer
TF_TOKEN_<host>environment variables in CI over baking credentials into files or the repository. - Store the token in a secrets manager and inject it at run time; never commit
credentials.tfrc.json. - Use organization/team tokens for automation and user tokens for humans, so rotating one does not break the other.
- Set explicit token expiry and rotate on a schedule, updating the CI secret in the same change.
- Pin the
hostnamein the backend block so a copied config cannot silently target the wrong host. - Trim whitespace and quotes when injecting tokens; a trailing newline is a common silent cause of 401s.
Related Errors
Required token could not be found— no credential stored at all, rather than a rejected one.Error: Failed to get existing workspaces: ... 403 Forbidden— authenticated but not permitted (RBAC), not a bad token.Error: workspace "..." not found— the token is valid but the named workspace does not exist or is not visible.no valid credential sources found— an AWS credential problem, not an HCP Terraform token problem.
Frequently Asked Questions
Where does terraform login store the token? It writes a JSON credentials block to ~/.terraform.d/credentials.tfrc.json keyed by hostname; delete or overwrite that entry to force re-authentication.
Why does CI get a 401 when my laptop works? Your laptop has a stored credential from terraform login, but CI has none unless you set TF_TOKEN_<host> or provide a credentials file; export the environment variable in the pipeline.
How do I build the TF_TOKEN_* variable name for a private host? Take the backend hostname and replace every dot with an underscore, so tfe.example.com becomes TF_TOKEN_tfe_example_com.
Could the token be valid but still rejected? Yes — if it is scoped to a different organization than the one in your cloud block, the backend returns 401/403; issue a token for the correct org. For more state-backend fixes, see the Terraform guides.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.