{"record":{"id":"e6f91ea781423da9","repo":"hashicorp/terraform","slug":"login-cancelled","errorCode":null,"errorMessage":"Login cancelled","messagePattern":"Login cancelled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"internal/command/login.go","lineNumber":373,"sourceCode":"// Synopsis implements cli.Command.\nfunc (c *LoginCommand) Synopsis() string {\n\treturn \"Obtain and save credentials for a remote host\"\n}\n\nfunc (c *LoginCommand) defaultOutputFile() string {\n\tif c.CLIConfigDir == \"\" {\n\t\treturn \"\" // no default available\n\t}\n\treturn filepath.Join(c.CLIConfigDir, \"credentials.tfrc.json\")\n}\n\nfunc (c *LoginCommand) interactiveGetTokenByCode(hostname svchost.Hostname, credsCtx *loginCredentialsContext, clientConfig *disco.OAuthClient) (*oauth2.Token, tfdiags.Diagnostics) {\n\tvar diags tfdiags.Diagnostics\n\n\tconfirm, confirmDiags := c.interactiveContextConsent(hostname, disco.OAuthAuthzCodeGrant, credsCtx)\n\tdiags = diags.Append(confirmDiags)\n\tif !confirm {\n\t\tdiags = diags.Append(errors.New(\"Login cancelled\"))\n\t\treturn nil, diags\n\t}\n\n\t// We'll use an entirely pseudo-random UUID for our temporary request\n\t// state. The OAuth server must echo this back to us in the callback\n\t// request to make it difficult for some other running process to\n\t// interfere by sending its own request to our temporary server.\n\treqState, err := uuid.GenerateUUID()\n\tif err != nil {\n\t\t// This should be very unlikely, but could potentially occur if e.g.\n\t\t// there's not enough pseudo-random entropy available.\n\t\tdiags = diags.Append(tfdiags.Sourceless(\n\t\t\ttfdiags.Error,\n\t\t\t\"Can't generate login request state\",\n\t\t\tfmt.Sprintf(\"Cannot generate random request identifier for login request: %s.\", err),\n\t\t))\n\t\treturn nil, diags\n\t}","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/command/login.go#L355-L391","documentation":"Thrown by `terraform login` during the OAuth authorization-code grant flow (login.go:367 interactiveGetTokenByCode). Before starting the OAuth callback server the command calls interactiveContextConsent() which prompts \"Do you want to proceed?\"; only the literal answer \"yes\" confirms. Anything else returns confirm=false, and line 373 appends this plain error to the diagnostics. It is a deliberate user-initiated cancellation, not a system failure.","triggerScenarios":"Running `terraform login <hostname>` against a host whose service discovery advertises an OAuth authorization-code grant, then answering the consent prompt with anything other than \"yes\" (\"no\", empty enter, a typo, or EOF on stdin).","commonSituations":"Operator runs `terraform login app.terraform.io` by mistake and answers \"no\" to abort; non-interactive shell where stdin closes (EOF) so the empty default is not \"yes\"; piped input that supplies \"Yes\" with a capital Y (strings.ToLower handles this) vs a stray space.","solutions":["If you intended to log in, re-run `terraform login <hostname>` and type exactly `yes` at the prompt.","If running in CI/non-interactive, skip `terraform login` and instead set a token via the TF_TOKEN_<hostname> environment variable or write a credentials block in ~/.terraform.d/credentials.tfrc.json.","If you wanted to cancel, ignore the message — no credentials were written."],"exampleFix":"# before (non-interactive, fails)\n terraform login app.terraform.io\n# after (set token directly, no prompt)\n export TF_TOKEN_app_terraform_io=\"<token>\"\n terraform init","handlingStrategy":"validation","validationCode":"// Before launching `terraform login`, check whether a prompt is even possible.\n if !isInteractive(stdin) || tokenAlreadyConfigured(hostname) {\n     // skip login, set TF_TOKEN_<hostname> or credentials file instead\n     return\n }","typeGuard":null,"tryCatchPattern":"// When shelling out to terraform login, expect exit!=0 on user cancel and do not treat it as a hard failure.\n out, err := exec.Command(\"terraform\", \"login\", host).CombinedOutput()\n if err != nil && bytes.Contains(out, []byte(\"Login cancelled\")) {\n     log.Println(\"login declined by user/operator\")\n     return\n }","preventionTips":["Pre-configure tokens via TF_TOKEN_<hostname> env vars or credentials.tfrc.json to avoid the interactive login flow entirely in automation.","When scripting, supply the consent answer only when stdin is a TTY; otherwise fail fast before launching login."],"tags":["login","oauth","interactive","cancellation"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}