Numba's error messages are long; knowing how to read them and where to look saves hours.
Most failures are a TypingError raised on the first call. The message is long, but it has a fixed structure: what operation failed (for example "No implementation of function Function(<built-in function add>) found for signature: (int64, unicode_type)"), the list of candidate implementations tried, and, at the end, the source line where it happened. Read the bottom first.
Common causes:
- a variable that takes two incompatible types in different branches, such as
Noneand an array, - an unsupported function or keyword argument,
- an untyped empty list (
[]that is never appended to), - passing an unsupported object (a pandas Series, a Python object) as an argument.
Debugging tools:
NUMBA_DISABLE_JIT=1in the environment makes all decorators no-ops, so you can usepdb, breakpoints and prints in the pure Python version.print()works in compiled code for simple values.f.inspect_types()shows the inferred type of every variable.with numba.objmode(result="float64"):runs a block in the interpreter from compiled code, for example to call an unsupported library or a timer. Declare the types of variables that leave the block. It is slow, so keep it out of hot loops.
Runtime errors behave differently from Python: raising exceptions works for simple cases, but without boundscheck indexing errors are not caught, and integer overflow is silent. When results look wrong rather than failing, compare with f.py_func on a small input.
Example
import time
import numpy as np
from numba import njit, objmode
from numba.core.errors import TypingError
@njit
def broken(flag):
x = 1
if flag:
x = "one" # int in one branch, str in the other
return x
try:
broken(True)
except TypingError as e:
print("Cannot unify" in str(e)) # True: the reason is near the end of the message
@njit
def timed_sum(a):
with objmode(t0="float64"): # interpreter block inside compiled code
t0 = time.perf_counter()
s = a.sum()
return s, t0 > 0
print(timed_sum(np.ones(10))) # (10.0, True)Remember
- Read a TypingError from the bottom: the failing source line is at the end
- NUMBA_DISABLE_JIT=1 lets you debug the pure Python version
- objmode runs a block in the interpreter with declared output types
Watch out for
- Leaving objmode blocks inside hot loops, which brings back interpreter overhead.