{"record":{"id":"897d0142b54493b9","repo":"chocolatey/choco","slug":"too-many-bad-attempts-stopping-before-application","errorCode":null,"errorMessage":"Too many bad attempts. Stopping before application crash.","messagePattern":"Too many bad attempts\\. Stopping before application crash\\.","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"error","filePath":"src/chocolatey/infrastructure/commandline/InteractivePrompt.cs","lineNumber":48,"sourceCode":"        private static Lazy<IConsole> _console = new Lazy<IConsole>(() => new Console());\r\n        private const int TimeoutInSeconds = 30;\r\n\r\n        [EditorBrowsable(EditorBrowsableState.Never)]\r\n        public static void InitializeWith(Lazy<IConsole> console)\r\n        {\r\n            _console = console;\r\n        }\r\n\r\n        private static IConsole Console\r\n        {\r\n            get { return _console.Value; }\r\n        }\r\n\r\n        public static string PromptForConfirmation(string prompt, IEnumerable<string> choices, string defaultChoice, bool requireAnswer, bool allowShortAnswer = true, bool shortPrompt = false, int repeat = 10, int timeoutInSeconds = 0)\r\n        {\r\n            if (repeat < 0)\r\n            {\r\n                throw new ApplicationException(\"Too many bad attempts. Stopping before application crash.\");\r\n            }\r\n\r\n            Ensure.That(() => prompt).NotNull();\r\n            Ensure.That(() => choices).NotNull();\r\n            Ensure\r\n                .That(() => choices)\r\n                .Meets(\r\n                    c => c.Count() > 0,\r\n                    (name, value) => { throw new ApplicationException(\"No choices passed in. Please ensure you pass choices\"); });\r\n\r\n            if (!string.IsNullOrWhiteSpace(defaultChoice))\r\n            {\r\n                Ensure\r\n                    .That(() => choices)\r\n                    .Meets(\r\n                        c => c.Contains(defaultChoice),\r\n                        (name, value) => { throw new ApplicationException(\"Default choice value must be one of the given choices.\"); });\r\n            }\r","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/chocolatey/choco/blob/0d5abdd10cc177a141e69547cad6935b419b6c17/src/chocolatey/infrastructure/commandline/InteractivePrompt.cs#L30-L66","documentation":"Thrown by InteractivePrompt.PromptForConfirmation when the `repeat` counter drops below zero. The method is designed to recurse (or loop) decrementing `repeat` each time the user supplies an invalid/empty answer; once retries are exhausted the count goes negative and this ApplicationException halts further prompting to avoid an unbounded or crash-prone loop.","triggerScenarios":"Calling PromptForConfirmation with a small or exhausted `repeat` value (default 10) and the user repeatedly giving input that matches none of the supplied choices, or pressing Enter with no defaultChoice set while requireAnswer is true. Each invalid iteration decrements repeat until it falls under 0.","commonSituations":"Non-interactive or scripted runs where stdin is closed/empty, so every prompt attempt is 'bad' and the retry budget is consumed instantly. Misconfigured prompts that supply choices that can never match the expected input format.","solutions":["Provide a non-empty defaultChoice that is a member of choices so an empty Enter yields a valid answer instead of burning a retry.","Increase the `repeat` argument if legitimate user mistakes are likely (e.g. pass repeat: 20).","Run in an interactive context with a real TTY, or pre-validate the caller's choices/defaultChoice so bad-input paths cannot recur indefinitely.","Pipe a valid answer into stdin when running non-interactively."],"exampleFix":"// before\nInteractivePrompt.PromptForConfirmation(prompt, choices, defaultChoice: null, requireAnswer: true);\n\n// after\nInteractivePrompt.PromptForConfirmation(prompt, choices, defaultChoice: choices.First(), requireAnswer: true);","handlingStrategy":"validation","validationCode":"if (!choices.Any()) throw new ArgumentException(\"choices must not be empty\");\nif (requireAnswer && string.IsNullOrWhiteSpace(defaultChoice))\n{\n    throw new ArgumentException(\"requireAnswer requires a non-empty defaultChoice present in choices\");\n}\nif (!string.IsNullOrWhiteSpace(defaultChoice) && !choices.Contains(defaultChoice))\n{\n    throw new ArgumentException(\"defaultChoice must be one of choices\");\n}\nvar safeRepeat = Math.Max(1, repeat);","typeGuard":null,"tryCatchPattern":"try\n{\n    answer = InteractivePrompt.PromptForConfirmation(prompt, choices, defaultChoice, requireAnswer, repeat: 10);\n}\ncatch (ApplicationException ex) when (ex.Message.Contains(\"Too many bad attempts\"))\n{\n    logger.Error(\"User input retries exhausted; falling back to default action.\");\n    answer = defaultChoice;\n}","preventionTips":["Always pass a defaultChoice that is a member of choices when running non-interactively.","Pre-feed a valid answer via stdin for scripted runs instead of relying on the retry budget.","Validate choices/defaultChoice shape before calling PromptForConfirmation."],"tags":["interactive","prompt","retry-exhausted","validation"],"backgroundTag":null,"analyzedSha":"0d5abdd10cc177a141e69547cad6935b419b6c17","analyzedAt":"2026-08-13T18:33:03.301Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}