Encountering a TypeError: got multiple values for argument is a rite of passage for almost every Python developer. Still, it usually appears when you least expect it, halting execution and leaving you staring at a function call that looks perfectly valid at first glance. On top of that, this error signals a fundamental conflict in how arguments are being passed to a function: Python has received the same argument twice, once by position and once by keyword, or twice via keyword arguments. Understanding why this happens requires a solid grasp of Python’s argument passing mechanics, specifically the interplay between positional arguments, keyword arguments, and parameter definitions Small thing, real impact..
Understanding the Core Mechanism
At the heart of this error lies Python’s function calling convention. So when you define a function, you create a signature consisting of parameters. When you call that function, you supply arguments.
- Positional arguments are matched to parameters from left to right.
- Keyword arguments (kwargs) are matched by parameter name.
*argscollects excess positional arguments into a tuple.**kwargscollects excess keyword arguments into a dictionary.
The rule is absolute: **a single parameter can only receive one value per function call.Practically speaking, ** If the mapping process attempts to assign a value to a parameter that has already been assigned a value, the interpreter raises the TypeError: got multiple values for argument exception. This protection prevents ambiguous behavior where a function wouldn't know which value to prioritize.
Common Scenarios Triggering the Error
While the error message is consistent, the code patterns that cause it vary. Recognizing these patterns is the fastest way to debug and fix the issue.
1. Mixing Positional and Keyword for the Same Parameter
This is the most frequent cause. It happens when a developer passes an argument by position and explicitly names it later in the call.
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
# ERROR: 'name' gets value "Alice" by position (1st arg)
# AND value "Bob" by keyword (name="Bob")
greet("Alice", name="Bob")
Here, "Alice" fills the first parameter name. Immediately after, name="Bob" attempts to fill name again. Python detects the collision and stops execution The details matter here. Took long enough..
2. Duplicate Keyword Arguments
Though less common in hand-written code, this occurs frequently when dynamically constructing dictionaries for unpacking (**kwargs).
def configure(host, port, timeout=30):
pass
params = {"host": "localhost", "port": 8080, "host": "127.That said, 0. 0.1"}
# Dictionary literals with duplicate keys keep the last value,
# but unpacking them passes the key twice conceptually if constructed dynamically.
# More realistically:
params = {"host": "localhost", "port": 8080}
params["host"] = "127.Worth adding: 0. 0.1" # Overwrite
configure(**params, host="remote.
In the example above, `**params` unpacks `host`, and the explicit `host="remote.server"` tries to assign it a second time.
### 3. The `*args` and `**kwargs` Trap
Functions accepting variadic arguments (`*args`, `**kwargs`) introduce a larger surface area for collisions. If a positional argument passed via `*args` corresponds to a named parameter, or if a key in `**kwargs` matches a formal parameter name, the error triggers.
```python
def process(data, mode="fast", *args, **kwargs):
pass
# 'mode' is a formal parameter.
# It gets "slow" from the 2nd positional arg.
# It gets "thorough" from kwargs.
process("dataset", "slow", mode="thorough") # ERROR
Here, the second positional argument "slow" binds to mode. The subsequent mode="thorough" creates the conflict It's one of those things that adds up..
4. Method Calls and self Confusion
When calling instance methods manually or via decorators, forgetting that self is the first positional argument often leads to this error Not complicated — just consistent..
class Calculator:
def add(self, a, b):
return a + b
calc = Calculator()
# 'calc' is passed as 'self' (positional).
Worth adding: # 'calc' is passed again as 'a' (positional). # '5' becomes 'b'.
Calculator.
The correct call is `calc.On top of that, add(5, 10)` or `Calculator. add(calc, 5, 10)`.
## Deep Dive: Parameter Types and Vulnerability
Not all parameters are equally susceptible. Understanding the parameter categories defined in PEP 362 (Function Signature Object) helps predict where collisions happen.
### Positional-Only Parameters (`/`)
Introduced in Python 3.Here's the thing — 8, parameters before a `/` in the signature *must* be passed positionally. They cannot be passed by keyword.
```python
def divmod(a, b, /):
return (a // b, a % b)
divmod(10, 5) # OK
divmod(a=10, b=5) # TypeError: divmod() got some positional-only arguments passed as keyword arguments
# Note: This raises a *different* error, not "multiple values".
Because they cannot be passed by keyword, positional-only parameters are immune to the "multiple values" error from keyword collisions. Even so, they can still collide if passed positionally twice via *args unpacking.
Keyword-Only Parameters (*)
Parameters after a * or *args must be passed by keyword. They are safe from positional collisions but highly vulnerable to keyword collisions (explicit keyword vs **kwargs) It's one of those things that adds up..
def connect(host, *, port, timeout=10):
pass
connect("localhost", port=8080, **{"port": 80, "timeout": 5})
# ERROR: 'port' passed explicitly and via **kwargs
Standard Parameters (Positional or Keyword)
These are the default parameters (e.g.Consider this: , def func(a, b=1)). They are vulnerable from both sides: positional overlap and keyword overlap. This is where the majority of multiple values errors originate.
Debugging Strategies
When the traceback points to a function call line, the fix isn't always obvious, especially in large codebases with heavy use of *args and **kwargs. Here is a systematic approach to resolving it Took long enough..
1. Read the Traceback Carefully
The error message explicitly names the problematic argument:
TypeError: greet() got multiple values for argument 'name'
Focus immediately on the parameter named (name in this case). Ignore other parameters for the moment Not complicated — just consistent..
2. Audit the Call Site
Look at the specific function call. Count the positional arguments. Map them to the function signature manually.
- Argument 1 $\to$ Parameter 1
- Argument 2 $\to$ Parameter 2
- ...
Check if any parameter appears in both the positional mapping and the keyword mapping Took long enough..
3. Inspect Unpacked Iterables and Mappings
If the call uses *args or **kwargs, you must know the runtime contents of those variables. Print them immediately before the call:
print(f"Positional args: {args}")
print(f"Keyword args: {kwargs}")
target_function(*args, **kwargs)
Look for overlapping keys in kwargs that match formal parameter names, or positional values
4. put to work IDE and Editor Features
Modern IDEs such as PyCharm, VS Code, and Spyder can display the expected signature of a callable right at the call site. By hovering over the function name or enabling “signature hint” plugins, you instantly see which parameters are positional‑only, which accept both positional and keyword, and which are keyword‑only. This visual cue eliminates the guesswork involved in manually mapping arguments Small thing, real impact..
If your workflow relies on a text editor without built‑in support, consider adding a linter rule that warns whenever a call contains more positional arguments than the function’s “positional‑only” count. The warning surfaces the exact moment a potential collision could arise.
5. Use Explicit Argument Labels in Complex Calls
When a function receives a mixture of positional and keyword arguments—especially inside a long expression or a lambda—rename the variables to make their intent obvious:
def schedule(event, *, priority=1, delay=0):
...
# Before (hard to track):
schedule(ev, pr, dl)
# After (clear):
schedule(event, priority=priority, delay=delay)
Explicit names act as a safety net; they prevent accidental duplication when the arguments are later unpacked from a container.
6. Guard Against Unintended Unpacking
A common source of the “multiple values” error is the expansion of a dictionary or list that already contains keys matching the function’s parameters. To mitigate this, separate the unpacking step:
call_kwargs = {"priority": 2, "delay": 3}
schedule(event, **call_kwargs) # risky if 'event' is also need the