From 5a2a544ae58672dda537cb820e2a6dbf88bdaa47 Mon Sep 17 00:00:00 2001 From: Friday Date: Tue, 17 Feb 2026 18:05:45 +0000 Subject: [PATCH] Raise clear error when multiple arguments accept multiple values When a command has more than one argument annotated with List[...], Click raises an opaque "TypeError: Cannot have two nargs < 0". This adds validation in Typer's parameter collection to detect multiple variadic arguments early and raise a clear UsageError explaining the constraint. Closes #260 --- tests/test_type_conversion.py | 12 ++++++++++++ typer/main.py | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/test_type_conversion.py b/tests/test_type_conversion.py index 83edd1ecb5..86afa5b882 100644 --- a/tests/test_type_conversion.py +++ b/tests/test_type_conversion.py @@ -168,3 +168,15 @@ def custom_click_type( result = runner.invoke(app, ["0x56"]) assert result.exit_code == 0 + + +def test_multiple_list_arguments_error(): + """Test that multiple List arguments raises a clear error (issue #260).""" + app = typer.Typer() + + @app.command() + def cmd(names: list[str], others: list[str]): + print(f"names={names}, others={others}") + + with pytest.raises(click.UsageError, match="Only one argument can take multiple values"): + runner.invoke(app, ["a", "b"], catch_exceptions=False) diff --git a/typer/main.py b/typer/main.py index f4f21bb844..bcd0dc6bc3 100644 --- a/typer/main.py +++ b/typer/main.py @@ -1376,6 +1376,16 @@ def get_params_convertors_ctx_param_name_from_function( if convertor: convertors[param_name] = convertor params.append(click_param) + variadic_args = [ + p.name for p in params if isinstance(p, click.Argument) and p.nargs < 0 + ] + if len(variadic_args) > 1: + names = ", ".join(f"'{n}'" for n in variadic_args) + raise click.UsageError( + f"Only one argument can take multiple values (nargs=-1), but " + f"{len(variadic_args)} were found: {names}. " + f"Use List[...] (or Sequence[...]) for at most one argument." + ) return params, convertors, context_param_name