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

  1. Generate a fresh token at `https://app.terraform.io/app/settings/tokens` (or the equivalent TFE settings page) and re-run `terraform login`.
  2. Confirm the token was copied in full — HCP Terraform tokens are 208+ characters; check for truncation.
  3. Verify the token is for the same hostname/instance you are logging in to.
  4. 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

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

Related errors


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)