hashicorp/terraform · error
Token is invalid
Error message
Token is invalid: %s
What it means
Thrown during `terraform login` after `client.Users.ReadCurrent` returns exactly `tfe.ErrUnauthorized`. The API client was constructed successfully (error 640 did not fire), the token was sent to the `/api/v2/account/details` endpoint, and the server responded with HTTP 401. This means the token format was acceptable to the client library but the server rejected it as invalid, expired, or revoked.
Solutions
- Generate a fresh token at `https://app.terraform.io/app/settings/tokens` (or the equivalent TFE settings page) and re-run `terraform login`.
- Confirm the token was copied in full — HCP Terraform tokens are 208+ characters; check for truncation.
- Verify the token is for the same hostname/instance you are logging in to.
- If the token was recently revoked or rotated, update any credential helpers or `.terraformrc` that may supply a stale value.
Example fix
// The token typed at the prompt is rejected by the server. // Re-generate: https://app.terraform.io/app/settings/tokens // Then: terraform login app.terraform.io // paste the NEW token at the 'Token for app.terraform.io:' prompt
Defensive patterns
Strategy: validation
Validate before calling
// Before scripting a login, sanity-check token length/format.
// HCP Terraform tokens are long opaque strings (typically 200+ chars).
token = strings.TrimSpace(token)
if len(token) < 100 {
return errors.New("token looks truncated; re-copy the full token from the UI")
} Type guard
null
Try / catch
// After login, detect 401 specifically:
if errors.Is(err, tfe.ErrUnauthorized) {
// prompt the user to regenerate the token
} Prevention
- Generate tokens with a clear expiration and rotation reminder.
- Store tokens in a credentials helper or secret manager rather than copy-pasting.
- Confirm the token's hostname/instance scope before use.
When it happens
Trigger: `client.Users.ReadCurrent` issues `GET /api/v2/account/details` with the `Authorization: Bearer <token>` header. The server returns 401, which go-tfe maps to `tfe.ErrUnauthorized`, and this branch (`err == tfe.ErrUnauthorized`) catches it distinctly from other failures.
Common situations: User pasted an expired or revoked API token; user pasted a token from a different HCP Terraform organization or a different TFE instance; token was truncated or had stray whitespace beyond what `TrimSpace` removed (e.g. embedded newline); token belongs to a team with no access to the current user scope.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Failed to create API client
- Failed to retrieve token
- Connection Error: StatusCode
- could not read state version output
- could not read state version outputs
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/f961efd6b29d94a0.
Report an issue: GitHub.
Appendix: source
Thrown at internal/command/login.go:662
diags := diags.Append(fmt.Errorf("Failed to retrieve token: %s", err))
return "", diags
}
token = strings.TrimSpace(token)
cfg := &tfe.Config{
Address: service.String(),
BasePath: service.Path,
Token: token,
Headers: make(http.Header),
}
client, err := tfe.NewClient(cfg)
if err != nil {
diags = diags.Append(fmt.Errorf("Failed to create API client: %s", err))
return "", diags
}
user, err := client.Users.ReadCurrent(context.Background())
if err == tfe.ErrUnauthorized {
diags = diags.Append(fmt.Errorf("Token is invalid: %s", err))
return "", diags
} else if err != nil {
diags = diags.Append(fmt.Errorf("Failed to retrieve user account details: %s", err))
return "", diags
}
c.Ui.Output(fmt.Sprintf(c.Colorize().Color("\nRetrieved token for user [bold]%s[reset]\n"), user.Username))
return svcauth.HostCredentialsToken(token), nil
}
func (c *LoginCommand) interactiveContextConsent(hostname svchost.Hostname, grantType disco.OAuthGrantType, credsCtx *loginCredentialsContext) (bool, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
mechanism := "OAuth"
if grantType == "" {
mechanism = "your browser"
}
c.Ui.Output(fmt.Sprintf("Terraform will request an API token for %s using %s.\n", hostname.ForDisplay(), mechanism))View on GitHub (pinned to d32a084675)