hashicorp/terraform · error
error asking for approval
Error message
error asking for approval: %w
What it means
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.
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.
Example fix
# before: piped input closes early, causing 'error asking for approval' echo yes | terraform apply # after: explicit non-interactive approval terraform apply -auto-approve
Defensive patterns
Strategy: try-catch
Validate before calling
// Decide whether to even show the approval prompt.
func shouldPrompt(op *backendrun.Operation) bool {
return op.UIIn != nil && op.AutoApprove == false && isInteractive(os.Stdin)
}
func isInteractive(f *os.File) bool {
fi, err := f.Stat()
return err == nil && (fi.Mode()&os.ModeCharDevice) != 0
} Type guard
null
Try / catch
v, err := op.UIIn.Input(stopCtx, opts)
if err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, io.EOF) {
// user-driven cancellation: report as cancelled, not as a hard error
op.View.Cancelled(op.PlanMode)
runningOp.Result = backendrun.OperationFailure
return
}
diags = diags.Append(fmt.Errorf("error asking for approval: %w", err))
op.ReportResult(runningOp, diags)
return
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to approve use of state storage provider
- Failed to request password
- Failed to request username
- Failed to retrieve token
- approved using the UI or API
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/4b863fb7352db973.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/local/backend_apply.go:190
}
desc = "Terraform will perform the actions described above.\n" +
"Only 'yes' will be accepted to approve."
}
// We'll show any accumulated warnings before we display the prompt,
// so the user can consider them when deciding how to answer.
if len(diags) > 0 {
op.View.Diagnostics(diags)
diags = nil // reset so we won't show the same diagnostics again later
}
v, err := op.UIIn.Input(stopCtx, &terraform.InputOpts{
Id: "approve",
Query: "\n" + query,
Description: desc,
})
if err != nil {
diags = diags.Append(fmt.Errorf("error asking for approval: %w", err))
op.ReportResult(runningOp, diags)
return
}
if v != "yes" {
op.View.Cancelled(op.PlanMode)
runningOp.Result = backendrun.OperationFailure
return
}
} else {
// If we didn't ask for confirmation from the user, and they have
// included any failing checks in their configuration, then they
// will see a very confusing output after the apply operation
// completes. This is because all the diagnostics from the plan
// operation will now be shown alongside the diagnostics from the
// apply operation. For check diagnostics, the plan output is
// irrelevant and simple noise after the same set of checks have
// been executed again during the apply stage. As such, we are going
// to remove all diagnostics marked as check diagnostics at thisView on GitHub (pinned to d32a084675)