{"record":{"id":"4b863fb7352db973","repo":"hashicorp/terraform","slug":"error-asking-for-approval-w","errorCode":null,"errorMessage":"error asking for approval: %w","messagePattern":"error asking for approval: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/local/backend_apply.go","lineNumber":190,"sourceCode":"\t\t\t\t}\n\t\t\t\tdesc = \"Terraform will perform the actions described above.\\n\" +\n\t\t\t\t\t\"Only 'yes' will be accepted to approve.\"\n\t\t\t}\n\n\t\t\t// We'll show any accumulated warnings before we display the prompt,\n\t\t\t// so the user can consider them when deciding how to answer.\n\t\t\tif len(diags) > 0 {\n\t\t\t\top.View.Diagnostics(diags)\n\t\t\t\tdiags = nil // reset so we won't show the same diagnostics again later\n\t\t\t}\n\n\t\t\tv, err := op.UIIn.Input(stopCtx, &terraform.InputOpts{\n\t\t\t\tId:          \"approve\",\n\t\t\t\tQuery:       \"\\n\" + query,\n\t\t\t\tDescription: desc,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tdiags = diags.Append(fmt.Errorf(\"error asking for approval: %w\", err))\n\t\t\t\top.ReportResult(runningOp, diags)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif v != \"yes\" {\n\t\t\t\top.View.Cancelled(op.PlanMode)\n\t\t\t\trunningOp.Result = backendrun.OperationFailure\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\t// If we didn't ask for confirmation from the user, and they have\n\t\t\t// included any failing checks in their configuration, then they\n\t\t\t// will see a very confusing output after the apply operation\n\t\t\t// completes. This is because all the diagnostics from the plan\n\t\t\t// operation will now be shown alongside the diagnostics from the\n\t\t\t// apply operation. For check diagnostics, the plan output is\n\t\t\t// irrelevant and simple noise after the same set of checks have\n\t\t\t// been executed again during the apply stage. As such, we are going\n\t\t\t// to remove all diagnostics marked as check diagnostics at this","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/local/backend_apply.go#L172-L208","documentation":"Thrown by the local backend's opApply when op.UIIn.Input returns an error while prompting the user to type 'yes' to approve an apply. It does NOT fire when the user types a wrong answer (that path sets OperationFailure); it fires only when the input mechanism itself fails.","triggerScenarios":"op.UIIn.Input(stopCtx, &terraform.InputOpts{Id:\"approve\",...}) returns a non-nil error. Common causes: stdin closed (EOF), the stop context was cancelled (Ctrl-C / interrupt), the terminal read failed, or -input was not disabled in a non-interactive environment that still routed through UIIn.","commonSituations":"Piping a plan into `terraform apply -` and the pipe closes before the prompt; running apply in CI without `-auto-approve` and without `-input=false`; user pressed Ctrl-C exactly as the prompt was shown; SSH session dropped mid-apply.","solutions":["Run non-interactive applies with -input=false and -auto-approve (or supply a plan file) so the prompt is never issued.","If interactive, ensure stdin is a TTY and is not being closed prematurely (no `</dev/null`, no truncated pipe).","Trap interrupts at the caller and treat context.Canceled on stopCtx as a clean cancellation rather than an error.","Check the wrapped err: if it is io.EOF or context.Canceled, surface a clearer 'apply cancelled' message instead of a raw error."],"exampleFix":"# before: piped input closes early, causing 'error asking for approval'\necho yes | terraform apply\n# after: explicit non-interactive approval\nterraform apply -auto-approve","handlingStrategy":"try-catch","validationCode":"// Decide whether to even show the approval prompt.\nfunc shouldPrompt(op *backendrun.Operation) bool {\n    return op.UIIn != nil && op.AutoApprove == false && isInteractive(os.Stdin)\n}\nfunc isInteractive(f *os.File) bool {\n    fi, err := f.Stat()\n    return err == nil && (fi.Mode()&os.ModeCharDevice) != 0\n}","typeGuard":"null","tryCatchPattern":"v, err := op.UIIn.Input(stopCtx, opts)\nif err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, io.EOF) {\n        // user-driven cancellation: report as cancelled, not as a hard error\n        op.View.Cancelled(op.PlanMode)\n        runningOp.Result = backendrun.OperationFailure\n        return\n    }\n    diags = diags.Append(fmt.Errorf(\"error asking for approval: %w\", err))\n    op.ReportResult(runningOp, diags)\n    return\n}","preventionTips":["Run non-interactive applies with -input=false -auto-approve (or pass a plan file).","Do not pipe input that can close mid-prompt; use -auto-approve for automation.","Handle context.Canceled and io.EOF distinctly from genuine I/O failures."],"tags":["local-backend","apply","interactive","ui-input","approval","stdin"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}