From ce692fa42b728a2f84ba43a8c290e4f090a01a44 Mon Sep 17 00:00:00 2001 From: lichuang9890-star Date: Mon, 6 Apr 2026 22:41:11 +0400 Subject: [PATCH] fix: show custom error messages when hide_input=True Previously, when hide_input=True and a type's convert() raised a UsageError (e.g. BadParameter), the custom error message was replaced with a generic 'Error: The value you entered was invalid.' message. The hide_input flag should only affect whether the input value is echoed during typing, not whether custom validation error messages are displayed. Custom error messages from type validation are written by the developer and do not contain the secret input value. Fixes #2809 --- src/click/termui.py | 5 +---- tests/test_utils.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/click/termui.py b/src/click/termui.py index 2e98a0771c..1f0edb9c88 100644 --- a/src/click/termui.py +++ b/src/click/termui.py @@ -177,10 +177,7 @@ def prompt_func(text: str) -> str: try: result = value_proc(value) except UsageError as e: - if hide_input: - echo(_("Error: The value you entered was invalid."), err=err) - else: - echo(_("Error: {e.message}").format(e=e), err=err) + echo(_("Error: {e.message}").format(e=e), err=err) continue if not confirmation_prompt: return result diff --git a/tests/test_utils.py b/tests/test_utils.py index 1b1575657c..a6f0357b1b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -746,3 +746,30 @@ def test_make_default_short_help(value, max_length, alter, expect): out = click.utils.make_default_short_help(value, max_length) assert out == expect + + +def test_hide_input_shows_custom_error(runner): + """With hide_input=True, custom error messages from type validation + should still be displayed, not swallowed by a generic message.""" + + class StrictPassword(click.ParamType): + name = "password" + + def convert(self, value, param, ctx): + if len(value) < 8: + self.fail("Password must be at least 8 characters", param, ctx) + return value + + @click.command() + @click.option( + "--pw", + prompt=True, + hide_input=True, + type=StrictPassword(), + ) + def cmd(pw): + click.echo(f"OK:{pw}") + + result = runner.invoke(cmd, input="short\nlong_enough_pw\n") + assert "Password must be at least 8 characters" in result.output + assert "OK:long_enough_pw" in result.output