Fix: Python TypeError: takes X positional arguments but Y were given
Part of: Python Errors
Quick Answer
How to fix Python TypeError takes positional arguments but were given caused by missing self, extra arguments, wrong function calls, and class method confusion.
The Error
You call a function or method and get:
TypeError: greet() takes 1 positional argument but 2 were givenOr variations:
TypeError: __init__() takes 1 positional argument but 2 were givenTypeError: process() takes 2 positional arguments but 3 were givenTypeError: calculate() takes 0 positional arguments but 1 was givenPython received more arguments than the function is defined to accept. The numbers in the error tell you exactly what happened — the function expected X arguments but got Y.
Why This Happens
The most confusing version is takes 1 positional argument but 2 were given when you only passed 1 argument. The hidden extra argument is self. When you call instance.method(arg), Python implicitly passes instance as self, making it 2 arguments total.
The error counts every parameter that Python had to bind, including the implicit self for instance methods and cls for class methods. That is why “takes 1 but 2 were given” looks impossible on a method declared as def m(self, x) — Python sees m(instance, x) and reports both arguments. The fix is rarely to remove an argument; almost always you forgot a parameter (self), changed the binding form (calling Class.method instead of instance.method), or passed an unpacked container twice.
The second common shape is a callback signature mismatch. Higher-order functions like map, filter, sorted(key=...), functools.reduce, and event handlers in Tkinter or asyncio all decide how many arguments to pass. Defining a callback that expects two arguments and handing it to map, which always calls with one, raises this error every time. Reading the docstring of the higher-order function tells you the expected arity before you write the callback.
Common causes:
- Forgot
selfin method definition. The method does not declareselfas its first parameter. - Called an instance method on the class.
MyClass.method(arg)passesargasself. - Passed too many arguments. The function simply does not accept that many.
- Decorator changed the signature. A decorator consumed or added arguments.
- Confused a function with a method. Passing
selfexplicitly when it should be implicit.
Platform and Environment Differences
The same TypeError reads differently depending on Python version, OS, and runtime.
Python 3.0–3.7 vs 3.8+ positional-only parameters. PEP 570 added the / syntax in Python 3.8 to mark parameters as positional-only:
def divmod_safe(a, b, /, mode="floor"): # a and b are positional-only
...In 3.8+ calling divmod_safe(a=1, b=2) raises TypeError: divmod_safe() got some positional-only arguments passed as keyword arguments. Many CPython built-ins (dict, int, str.replace) have been positional-only forever, but in 3.7 the error message read takes no keyword arguments. From 3.8 onward the message changed to the modern form. If you grepped a Stack Overflow thread and the wording does not match, you may be reading a Python 3.7 era answer.
Keyword-only arguments after *. PEP 3102 (Python 3.0) introduced keyword-only arguments:
def connect(host, *, timeout=10): # timeout is keyword-only
...
connect("db.local", 30)
# TypeError: connect() takes 1 positional argument but 2 were givenThe error wording is the same as for missing self, but the cause is the * separator. Inspect the signature before adding the argument.
pickle and multiprocessing differ across OSes. On Linux, multiprocessing defaults to the fork start method, which copies the parent process’s memory and preserves callable references directly. On macOS (since Python 3.8) and Windows the default is spawn, which serializes arguments through pickle. A class method passed to Pool.map works under fork because the worker inherits the class definition, but under spawn the callable is re-imported and its signature might differ if the module has changed in the child’s import path. The error often reads takes 1 positional argument but 2 were given because the worker process re-imported a module without the latest edit. Always restart child processes after editing callables, and avoid passing bound methods to Pool.map — pass top-level functions instead.
Cython vs CPython. Cython compiles .pyx files into C extensions. A Cython-compiled function exposes its signature through C metadata, not Python’s bytecode-level argument table. The error message can read takes exactly N arguments (the older C-API wording) rather than takes N positional arguments but Y were given. The cause is identical, but Stack Overflow answers that grep for the modern wording miss Cython hits. If your traceback shows .pyx files, the same fix applies: count the parameters and verify the call.
Type hints are inferred but not enforced at runtime. A signature like def f(x: int, y: int) -> int: only tells the type checker. If you pass three arguments, the TypeError still fires from the interpreter, not from the annotations. Tools like mypy and pyright catch the mismatch at lint time but never affect the runtime error wording. For broader type-checker errors, see Fix: Python mypy type error.
Decorators silently change arity. A decorator that uses def wrapper(*args, **kwargs) preserves the call signature for users but breaks introspection. A decorator that uses def wrapper(arg) drops every extra argument. The error then surfaces inside the decorator’s body, not at the original function definition. functools.wraps(fn) preserves the docstring and name but does not restore the signature. Use functools.wraps plus *args, **kwargs whenever a decorator should be transparent.
Async vs sync callable confusion. Passing a coroutine function (async def foo) where a regular callable is expected can show as the same error if the wrapper inspects the signature with inspect.signature and treats the implicit self differently. The fix is usually inspect.iscoroutinefunction(fn) plus a separate code path that schedules the coroutine on an event loop rather than calling it directly.
Fix 1: Add self to Instance Methods
The most common cause. If you define a method inside a class without self, calling it on an instance passes the instance as the first argument, shifting everything:
Broken:
class Calculator:
def add(a, b): # Missing self!
return a + b
calc = Calculator()
calc.add(2, 3)
# TypeError: add() takes 2 positional arguments but 3 were given
# Python sent: add(calc, 2, 3) — 3 arguments, not 2Fixed:
class Calculator:
def add(self, a, b):
return a + b
calc = Calculator()
calc.add(2, 3) # Works — Python sends add(calc, 2, 3)Every instance method must have self as its first parameter. Python passes the instance automatically.
Pro Tip: If the method does not need access to
self(no instance state), use@staticmethod:class Calculator: @staticmethod def add(a, b): return a + b Calculator.add(2, 3) # Works without self
Fix 2: Fix init Argument Count
A common variant when creating class instances:
Broken:
class User:
def __init__(self): # Only accepts self
pass
user = User("Alice")
# TypeError: __init__() takes 1 positional argument but 2 were givenFixed — add the parameter:
class User:
def __init__(self, name):
self.name = name
user = User("Alice") # WorksOr accept optional arguments:
class User:
def __init__(self, name="Anonymous"):
self.name = name
User() # Works — name defaults to "Anonymous"
User("Alice") # WorksFix 3: Fix Extra Arguments
You might be passing more arguments than the function accepts:
def greet(name):
print(f"Hello, {name}!")
greet("Alice", "Bob")
# TypeError: greet() takes 1 positional argument but 2 were givenFix: Check the function signature:
import inspect
print(inspect.signature(greet))
# (name)Either pass fewer arguments or update the function to accept more:
def greet(name, *others):
print(f"Hello, {name}!")
for other in others:
print(f"Hello, {other}!")
greet("Alice", "Bob") # WorksFix 4: Fix Callback Argument Mismatches
When using callbacks with map, filter, sorted, or event handlers, the caller determines how many arguments your function receives:
Broken:
names = ["Alice", "Bob", "Charlie"]
def format_name(name, index):
return f"{index}: {name}"
list(map(format_name, names))
# TypeError: format_name() missing 1 required positional argument: 'index'map() passes one argument per iterable. To get the index too:
Fixed:
list(map(format_name, names, range(len(names))))
# Or better:
[f"{i}: {name}" for i, name in enumerate(names)]Broken with sorted:
def compare(a, b):
return len(a) - len(b)
sorted(names, key=compare)
# TypeError: compare() takes 2 positional arguments but 1 was givensorted(key=...) passes one argument to the key function, not two:
Fixed:
sorted(names, key=len)
# Or:
sorted(names, key=lambda name: len(name))For the inverse error (missing required arguments), see Fix: Python TypeError: missing required positional argument.
Fix 5: Fix Property Decorator Issues
If you accidentally call a property like a regular method:
class User:
@property
def name(self):
return self._name
user = User()
user.name() # TypeError: 'str' object is not callableProperties are accessed without parentheses: user.name, not user.name().
The reverse problem — defining a method but accessing it as a property:
class User:
def get_name(self):
return self._name
user = User()
print(user.get_name) # Prints the method object, not the name
print(user.get_name()) # Correct — calls the methodFix 6: Fix Class Method vs Static Method
@classmethod receives cls as the first argument:
class User:
count = 0
@classmethod
def create(cls, name):
cls.count += 1
return cls(name)@staticmethod receives no implicit arguments:
class MathUtils:
@staticmethod
def add(a, b):
return a + bCommon mistake — using @classmethod but forgetting cls:
class Config:
@classmethod
def from_file(path): # Missing cls!
pass
Config.from_file("config.yaml")
# TypeError: from_file() takes 1 positional argument but 2 were givenFixed:
class Config:
@classmethod
def from_file(cls, path):
return cls()Fix 7: Fix *args and **kwargs
Use *args to accept any number of positional arguments:
def log(*messages):
for msg in messages:
print(msg)
log("hello") # 1 argument — works
log("hello", "world", "!") # 3 arguments — worksUse **kwargs for keyword arguments:
def create_user(**kwargs):
print(kwargs)
create_user(name="Alice", age=30)
# {'name': 'Alice', 'age': 30}Combine both:
def flexible(required, *args, **kwargs):
print(f"Required: {required}")
print(f"Extra positional: {args}")
print(f"Keyword: {kwargs}")
flexible("hello", 1, 2, 3, debug=True)Common Mistake: Passing a list as a single argument when you meant to unpack it:
def add(a, b, c): return a + b + c numbers = [1, 2, 3] add(numbers) # TypeError: takes 3 but 1 given add(*numbers) # Works — unpacks to add(1, 2, 3)
Fix 8: Debug the Error
When the error is unclear, inspect the call:
import inspect
# Check the expected signature
print(inspect.signature(my_function))
# Check all parameters
for name, param in inspect.signature(my_function).parameters.items():
print(f" {name}: kind={param.kind.name}, default={param.default}")Count the arguments manually:
def process(self, data, format, verbose=False):
pass
# instance.process(data, "json", True)
# Python sends: process(instance, data, "json", True) = 4 arguments
# Signature expects: self, data, format, verbose = 4 parametersRemember that self and cls count as arguments. Python reports the total including these implicit arguments.
Still Not Working?
Check for metaclasses. Custom metaclasses can change how __init__ and __new__ work, altering the expected argument count.
Check for __call__. If an object implements __call__, calling it like a function passes arguments to __call__, which needs self:
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, value): # Needs self!
return value * self.factor
double = Multiplier(2)
double(5) # 10 — calls __call__(self, 5)Check for circular imports. A circular import might cause a class to be partially loaded, making methods unavailable. See Fix: Python ImportError: circular import.
Check for name shadowing. A local variable might shadow the function you intend to call:
len = 5 # Shadows the built-in len()
len([1, 2, 3]) # TypeError: 'int' object is not callableCheck multiprocessing.Pool.map callable shape. Under the spawn start method (default on macOS and Windows), the worker process re-imports your module. If the callable is a bound instance method, the binding is re-created with the freshly imported class — and any local edits since the parent started are visible. The argument count can shift between runs. Pass a top-level function and explicit positional arguments via Pool.starmap instead of using bound methods.
Check decorator stacking order. Two decorators that both wrap with (*args, **kwargs) are fine. A decorator that wraps with (arg) followed by one that wraps with (*args, **kwargs) drops everything after the first argument. Read the decorators from bottom to top — the closest one to def runs first.
Check that functools.partial did not pre-fill an argument you also pass.
from functools import partial
hello = partial(print, "Hello")
hello("World", "!") # OK — print accepts *args
fixed = partial(greet, "Alice")
fixed("Bob") # TypeError if greet takes only one positional argumentCheck the actual Python version running. A virtualenv may shadow python with an older interpreter where positional-only syntax does not exist. Run python --version and which python to confirm.
If the error involves None instead of too many arguments, see Fix: TypeError: ‘NoneType’ object is not subscriptable.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: joblib Not Working — Parallel Backends, Memory Cache, and Pickling Errors
How to fix joblib errors — Parallel n_jobs slower than expected, Memory cache miss, backend loky vs threading vs multiprocessing, pickling lambda not supported, dump load file size, and pytest interference.
Fix: Marshmallow Not Working — Schema Errors, Load vs Dump, and Field Validation
How to fix Marshmallow errors — Schema not validated on dump, ValidationError messages format, unknown field handling, missing vs default, post_load object construction, and Marshmallow 3 to 4 migration.
Fix: Pipenv Not Working — Lock File Generation, Shell Activation, and Dependency Resolution
How to fix Pipenv errors — pipenv lock takes forever, Pipfile.lock not generated, shell activation broken, no virtualenv created, dependency conflict, and migration to uv or Poetry.
Fix: Copier Not Working — Template Updates, Question Conditions, and Migrations
How to fix Copier errors — copier.yml not found, conditional questions not appearing, update breaks generated project, migrations between versions, Jinja vs YAML escaping, and answers file conflict.