{"record":{"id":"98e7a2cac396ffe1","repo":"hashicorp/terraform","slug":"error-asking-s-v","errorCode":null,"errorMessage":"Error asking %s: %v","messagePattern":"Error asking (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote/backend_common.go","lineNumber":557,"sourceCode":"\n\t\t\t\t\tif err == errRunDiscarded {\n\t\t\t\t\t\terr = errApplyDiscarded\n\t\t\t\t\t\tif op.PlanMode == plans.DestroyMode {\n\t\t\t\t\t\t\terr = errDestroyDiscarded\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tresult <- err\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\tresult <- func() error {\n\t\tv, err := op.UIIn.Input(doneCtx, opts)\n\t\tif err != nil && err != context.Canceled && stopCtx.Err() != context.Canceled {\n\t\t\treturn fmt.Errorf(\"Error asking %s: %v\", opts.Id, err)\n\t\t}\n\n\t\t// We return the error of our parent channel as we don't\n\t\t// care about the error of the doneCtx which is only used\n\t\t// within this function. So if the doneCtx was canceled\n\t\t// because stopCtx was canceled, this will properly return\n\t\t// a context.Canceled error and otherwise it returns nil.\n\t\tif doneCtx.Err() == context.Canceled || stopCtx.Err() == context.Canceled {\n\t\t\treturn stopCtx.Err()\n\t\t}\n\n\t\t// Make sure we cancel the context here so the loop that\n\t\t// checks for external changes to the run is ended before\n\t\t// we start to make changes ourselves.\n\t\tcancel()\n\n\t\tif v != keyword {\n\t\t\t// Retrieve the run again to get its current status.","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote/backend_common.go#L539-L575","documentation":"Returned inside the confirm helper when op.UIIn.Input returns a non-nil error that is neither context.Canceled nor a parent-cancellation. The %s is opts.Id (e.g. 'override', 'approval'); the %v is the underlying input error. It indicates the interactive input subsystem itself failed.","triggerScenarios":"op.UIIn.Input(doneCtx, opts) errors while stopCtx is still alive. Caused by a closed/missing TTY, a broken input adapter, an EOF on stdin, or an internal error in the UI input implementation.","commonSituations":"Running in a non-interactive shell without -auto-approve; stdin redirected from a file that ended; terminal disconnected; custom UIIn implementation throwing; SSH session dropped mid-prompt.","solutions":["Run the command in a real TTY, or pass '-auto-approve' / '-input=false' for non-interactive contexts.","Inspect the wrapped error (%v) for the specific input cause (EOF, adapter error).","Ensure stdin is connected and not prematurely closed in CI.","Validate any custom UIIn adapter returns nil on successful input."],"exampleFix":"# before (fails in CI - no TTY)\nterraform apply\n# after (non-interactive)\nterraform apply -auto-approve","handlingStrategy":"validation","validationCode":"// Detect non-interactive contexts up front and switch to auto-approve.\nfunc shouldAutoApprove(op *backendrun.Operation) bool {\n    return op.UIIn == nil || !isTTY()\n}","typeGuard":null,"tryCatchPattern":"// Distinguish cancellation from genuine input errors.\nif _, err := op.UIIn.Input(ctx, opts); err != nil {\n    if errors.Is(err, context.Canceled) { return stopCtx.Err() }\n    return fmt.Errorf(\"input for %s failed (%w); run with -auto-approve in non-interactive shells\", opts.Id, err)\n}","preventionTips":["Use -input=false / -auto-approve in CI and non-TTY shells.","Validate custom UIIn adapters with unit tests covering success and error cases.","Keep stdin connected for the full prompt duration."],"tags":["backend","remote-backend","interactive","input","tty","ui","go"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}