Passing invalid arguments to a function is one of the most frequent causes of runtime errors in Python. When the type, value, count, or format of an argument doesn’t match what the function expects, Python raises clear exceptions — usually TypeError (wrong type), ValueError (bad value), or IndexError/KeyError (missing element). In production code, these can crash your program or produce silent bugs if unhandled. In 2026, robust functions detect invalid arguments early, raise meaningful errors, and provide helpful feedback — turning crashes into controlled, debuggable failures.
Here’s a complete, practical guide to what happens when invalid arguments are passed, how to catch and handle them gracefully, and modern best practices that make your code resilient and user-friendly.
Start with the most common case: a function expecting numbers gets a string instead. Python attempts the operation and fails with a TypeError — often with a clear message about incompatible types.
def double(num: float) -> float:
"""Double a number."""
return num * 2
# Valid call
print(double(5)) # 10.0
# Invalid argument type
try:
print(double("5")) # TypeError: can't multiply sequence by non-int of type 'str'
except TypeError as e:
print(f"Type error: {e}")
Even more dangerous: silent bugs when the wrong type “works” unexpectedly. Strings support multiplication by integers — so "hello" * 3 repeats the string — which might hide the real problem until much later in the program.
def repeat_text(text: str, times: int = 3) -> str:
return text * times
# Looks fine — but wrong intent
print(repeat_text(5)) # TypeError: can't multiply sequence by non-int of type 'int'
# Oops — intended to repeat a string, but passed a number
Real-world pattern: user input, file parsing, or API data often arrives as strings — always convert safely and validate ranges/values.
def calculate_rectangle_area(width_str: str, height_str: str) -> float:
"""Calculate area from string inputs — validate and convert."""
try:
width = float(width_str)
height = float(height_str)
if width <= 0 or height <= 0:
raise ValueError("Width and height must be positive numbers")
return width * height
except ValueError as e:
print(f"Invalid input: {e}")
return 0.0
except TypeError:
print("Inputs must be numeric strings")
return 0.0
print(calculate_rectangle_area("5.5", "4")) # 22.0
print(calculate_rectangle_area("abc", "4")) # Invalid input: could not convert string...
print(calculate_rectangle_area("10", "-3")) # Invalid input: Width and height must be...
Best practices make invalid argument handling predictable and developer-friendly. Use type hints everywhere — they document expectations and enable static checking with mypy/pylance. Validate inputs early — check types with isinstance(), ranges with if, and formats before heavy computation. Raise specific exceptions — TypeError for wrong types, ValueError for bad values, custom exceptions for domain rules. Provide clear error messages — include the bad value and expected format/range. Prefer raise over returning None or magic values — exceptions force callers to handle errors explicitly. Use try/except around conversions — especially float(), int(), bool() from user input/files/APIs. Modern tip: use libraries like pydantic or attrs for automatic validation — they check types, ranges, constraints, and generate nice, structured errors. Another powerful option: structural pattern matching (Python 3.10+) in except blocks for fine-grained handling. In production, log invalid calls — use logging.warning() or logging.error() to track bad inputs without crashing.
Passing invalid arguments is inevitable — especially with user input, files, APIs, or external data. In 2026, don’t let it crash your program. Use type hints to document, validate early, raise meaningful exceptions, and handle conversion failures gracefully. Build functions that fail fast and clearly when misused — your code becomes more robust, easier to debug, and production-ready.
Next time you accept input or call a function — assume it might be wrong. Validate, convert safely, and communicate errors clearly. That’s the difference between fragile code and reliable systems.