TypeError: expected string or bytes-like object (tested fix)
TypeError: expected string or bytes-like object, got 'NoneType' comes from the re module: you passed None, a number, NaN or a file object where it needs a string. We reproduced each case on Python 3.8, 3.11 and 3.13 and tested the fix.
1. Cause: re got something that is not a string
import re, sys
print(sys.version.split()[0])
for value in [None, 42, float("nan"), b"bytes ok", ["a", "b"]]:
try:
re.sub(r"\s+", " ", value)
except TypeError as e:
print(f"{value!r:12} TypeError: {e}")
Output:
3.13.5
None TypeError: expected string or bytes-like object, got 'NoneType'
42 TypeError: expected string or bytes-like object, got 'int'
nan TypeError: expected string or bytes-like object, got 'float'
b'bytes ok' TypeError: cannot use a string pattern on a bytes-like object
['a', 'b'] TypeError: expected string or bytes-like object, got 'list'
Every re function (sub, search, match, findall, split) needs a str (or bytes) to search. Since Python 3.11 the message ends with the type it got, which tells you the cause straight away. On Python 3.8 the same calls say only expected string or bytes-like object:
3.8.20
None TypeError: expected string or bytes-like object
42 TypeError: expected string or bytes-like object
nan TypeError: expected string or bytes-like object
b'bytes ok' TypeError: cannot use a string pattern on a bytes-like object
['a', 'b'] TypeError: expected string or bytes-like object
A float is almost always NaN: pandas reads an empty CSV cell as NaN in a text column, so df["col"].apply(lambda s: re.sub(...)) fails on the first blank row. (The pandas .str methods, such as df["col"].str.replace(pattern, "", regex=True), skip NaN for you.)
2. The usual source: a missing value (None)
# Typical source: a missing field, or an empty cell (NaN) in CSV/pandas data
import re, json
rows = json.loads('[{"phone": "555-0101"}, {"phone": null}]')
for row in rows:
try:
print(re.sub(r"\D", "", row["phone"]))
except TypeError as e:
print("TypeError:", e)
Output:
5550101
TypeError: expected string or bytes-like object, got 'NoneType'
JSON null, a database NULL, dict.get() on a missing key, and a function that forgot to return all give None. The first row works and the second one crashes.
3. Fix: handle None/NaN explicitly, then convert with str()
import re
def digits(value):
if value is None or value != value: # None or NaN (NaN != NaN)
return ""
return re.sub(r"\D", "", str(value))
for v in ["555-0101", None, float("nan"), 5550101]:
print(repr(v), "->", repr(digits(v)))
Output:
'555-0101' -> '5550101'
None -> ''
nan -> ''
5550101 -> '5550101'
Decide what an empty value should become (here an empty string) instead of calling str(None), which gives the text "None" and lets bad data through. value != value is True only for NaN, so it catches NaN without importing math or pandas.
4. A file object or bytes instead of the text
# re.findall on a whole file object, or on bytes with a str pattern
import re, io
f = io.StringIO("id=1\nid=2\n")
try:
re.findall(r"id=(\d)", f)
except TypeError as e:
print("TypeError:", e)
print(re.findall(r"id=(\d)", f.getvalue()))
try:
re.findall(r"id=(\d)", b"id=1")
except TypeError as e:
print("TypeError:", e)
print(re.findall(rb"id=(\d)", b"id=1"))
Output:
TypeError: expected string or bytes-like object, got '_io.StringIO'
['1', '2']
TypeError: cannot use a string pattern on a bytes-like object
[b'1']
Pass f.read() (or loop over lines), not the file object itself. Bytes are accepted but need a bytes pattern (rb"..."); a str pattern on bytes gives a different error, cannot use a string pattern on a bytes-like object. Either decode the bytes first or make the pattern bytes too.
Related: a bytes-like object is required, not 'str' ยท object is not iterable.
Frequently asked questions
What does expected string or bytes-like object, got 'NoneType' mean?
A re function such as re.sub or re.search received None, usually from a missing JSON/database value or a function without a return.
Why does it say got 'float'?
The value is almost always NaN, which pandas uses for empty cells. Check for it with value != value, or use the pandas .str methods, which skip NaN.
Should I just wrap the value in str()?
Only after handling None and NaN: str(None) is the text 'None' and str(nan) is 'nan', which then silently pass through your regex.
Written with AI assistance. Measured on 2026-10-23 with Python 3.13.5 on Debian, plus 3.11.17 and 3.8.20 in python:alpine containers: re.sub with None, int, NaN, bytes and a list; a JSON null field; a None/NaN-safe fix; and a file object passed to re.findall. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.