NoneType object cannot be interpreted as an integer (tested)

TypeError: 'NoneType' object cannot be interpreted as an integer means range() or a similar call got None. We traced where that None usually comes from on Python 3.13.5 and found three calls that accept it without any error.

1. The usual cause: a function that doesn't return

def count_rows(rows):
    n = len(rows)
    print("found", n, "rows")   # forgot: return n

total = count_rows(["a", "b", "c"])
print("total is", total)
for i in range(total):
    print(i)

Output:

found 3 rows
total is None
Traceback (most recent call last):
  File "/tmp/ni/b1.py", line 7, in <module>
    for i in range(total):
             ~~~~~^^^^^^^
TypeError: 'NoneType' object cannot be interpreted as an integer

Measured on Python 3.13.5: the function prints the count, so it looks right, but without a return it gives back None, and range(None) fails one line later. When you see this error, print the variable passed to range() and follow it back to where it was assigned.

2. Same None, different errors (and some silent passes)

import random, itertools
n = None   # e.g. a function that forgot to return
checks = {
    "range(n)":          lambda: range(n),
    "'x'.ljust(n)":      lambda: "x".ljust(n),
    "chr(n)":            lambda: chr(n),
    "[1, 2].pop(n)":     lambda: [1, 2].pop(n),
    "'ab' * n":          lambda: "ab" * n,
    "random.randint(1, n)": lambda: random.randint(1, n),
    "'abc'[n:2]":        lambda: "abc"[n:2],
    "islice('abc', n)":  lambda: list(itertools.islice("abc", n)),
    "round(1.5, n)":     lambda: round(1.5, n),
}
for name, f in checks.items():
    try:
        print(f"{name:22} -> OK {f()!r}")
    except TypeError as e:
        print(f"{name:22} -> TypeError: {e}")

Output:

range(n)               -> TypeError: 'NoneType' object cannot be interpreted as an integer
'x'.ljust(n)           -> TypeError: 'NoneType' object cannot be interpreted as an integer
chr(n)                 -> TypeError: 'NoneType' object cannot be interpreted as an integer
[1, 2].pop(n)          -> TypeError: 'NoneType' object cannot be interpreted as an integer
'ab' * n               -> TypeError: can't multiply sequence by non-int of type 'NoneType'
random.randint(1, n)   -> TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
'abc'[n:2]             -> OK 'ab'
islice('abc', n)       -> OK ['a', 'b', 'c']
round(1.5, n)          -> OK 2

Measured: anything that needs a true integer (range, ljust, chr, pop, to_bytes, os.read) gives this exact message. The same None elsewhere gives a different message, so search for "None" in your traceback, not just this string. Three calls accept None without complaint because there it means "not given": a slice bound, islice's stop, and round's digits. In those, a missing value silently means "all of it". More on tracing a None in our NoneType has no attribute guide.

3. dict.get(), environment variables and division

import os
os.environ["WORKERS"] = "4"
config = {"retries": 3}
cases = {
    "config.get('workers')": lambda: config.get("workers"),
    "os.environ['WORKERS']": lambda: os.environ["WORKERS"],
    "10 / 2":                lambda: 10 / 2,
}
for name, get in cases.items():
    try:
        range(get())
        print(name, "-> OK")
    except TypeError as e:
        print(name, "->", e)

Output:

config.get('workers') -> 'NoneType' object cannot be interpreted as an integer
os.environ['WORKERS'] -> 'str' object cannot be interpreted as an integer
10 / 2 -> 'float' object cannot be interpreted as an integer

Measured: dict.get() returns None for a missing (or misspelled) key; give it a default, config.get("workers", 4). Environment variables are always strings, so convert with int(). And / always returns a float, even 10 / 2; use // when you need an integer count.

4. Fail early with a clear message

import operator

def as_count(value, name):
    if value is None:
        raise ValueError(f"{name} is None; did a function forget to return?")
    if isinstance(value, str):
        value = int(value)
    return operator.index(value)   # rejects floats like 5.0

for v in [3, "4", None, 5.0]:
    try:
        print(repr(v), "->", list(range(as_count(v, "count"))))
    except (ValueError, TypeError) as e:
        print(repr(v), "->", type(e).__name__ + ":", e)

Output:

3 -> [0, 1, 2]
'4' -> [0, 1, 2, 3]
None -> ValueError: count is None; did a function forget to return?
5.0 -> TypeError: 'float' object cannot be interpreted as an integer

Measured: operator.index() accepts exactly what range() accepts, so it rejects 5.0 too. Checking for None where the value enters your code gives a message that names the variable instead of a traceback deep in a loop.

Frequently asked questions

What does TypeError: 'NoneType' object cannot be interpreted as an integer mean?

A function that needs an integer, usually range(), got None. We measured the most common cause on Python 3.13.5: a function that forgot to return its result.

Why is my variable None when I pass it to range()?

It came from a function with no return, a dict.get() on a missing key, or a method like list.sort() that returns None. We measured the first two.

Does every function raise this error for None?

No. We measured range, ljust, chr and pop giving this message, 'ab' * None and random.randint giving different TypeErrors, and slicing, islice and round accepting None silently.

Why do I get 'str' or 'float' object cannot be interpreted as an integer?

Same error, other types: environment variables are strings (use int()), and / always returns a float (use //). We measured both.

Written with AI assistance. Measured on 2026-10-09 with Python 3.13.5: a function without return passed to range(), nine built-in calls given None, dict.get/environment/division inputs, and an operator.index validator. Every block was run verbatim and its output pasted from that run. PlainHeaders is our extension; everything else here is built-in Python.