Python TypeError: unsupported operand type(s)
Fix Python TypeError when operators are applied to incompatible types, such as str + int or None + float, and add explicit conversions or validation.
Symptoms
- TypeError: unsupported operand type(s) for +: 'int' and 'str'
- TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'
- The error appears only when data comes from user input or a file
Possible causes
- Values read from input(), env vars, or CSV are strings, not numbers
- A function returns None on some paths and is used in arithmetic
- Mixing Python types in a loop without conversion
- A pandas or numpy value has an unexpected dtype
Diagnosis steps
Print the operand types at the failing line
print(type(a), type(b))Interpretation
The two concrete types tell you exactly which side needs conversion or guarding.
Trace where each operand originates
Interpretation
Input from files and env is always str; None usually means a missing return.
Confirm with a minimal reproduction
python -c "print('1' + 1)"Interpretation
Reproducing 'int' and 'str' shows the class of bug and the needed fix.
Root cause
Python does not coerce across incompatible types for arithmetic. A string from text input, a None from a missing return, or a mismatched dtype flowing into an operator raises TypeError. The fix is a conversion or a guard at the boundary where the wrong type enters.
Fix
Convert at the boundary: int()/float() for parsed numbers, wrap with float(...) after validating, and reject empty strings. For functions that may return None, return a sentinel or raise early instead. Use a dtype check for arrays and coerce with pandas .astype.
Verify the fix
Re-run with the same input; the operation completes and prints the expected numeric result. Add a test that feeds a string input and asserts the converted output.
Symptoms
Arithmetic fails with a message like unsupported operand type(s) for +: 'int' and 'str'. It usually happens only with real input, not with the hard-coded values used during development.
Diagnosis
Print the concrete types:
total = 0
for raw in values:
print(type(raw))
total += raw
If raw prints <class 'str'>, that is the source. A NoneType operand usually means a helper returned nothing.
Fix
Convert at the boundary and reject bad input:
def to_number(raw: str) -> float:
try:
return float(raw)
except ValueError as exc:
raise ValueError(f'not a number: {raw!r}') from exc
total = sum(to_number(v) for v in values)
Verification
Re-run with the same data; the sum is numeric and no TypeError appears. Feed a non-numeric string in a test and assert a clear ValueError is raised.
Additional Notes
Boundary conversion is the durable pattern: parse raw text into numbers once, at the edge where untrusted data enters, and let the rest of the code work with well-typed values. Functions that may return nothing should instead raise or return a sentinel, so callers never perform arithmetic on an absent value. Typing annotations and a static checker catch many of these mistakes before runtime, while a small helper that converts and reports the offending value turns a cryptic operand error into a clear message naming exactly which input was invalid and why.