pytest-dev/pytest · error · ValueError
relative tolerance can't be NaN.
Error message
relative tolerance can't be NaN.
What it means
Raised by ApproxScalar.tolerance when the computed relative tolerance is NaN. This happens when rel is NaN or when abs(expected) is NaN (i.e. the expected value itself is NaN), since the product becomes NaN.
Source
Thrown at src/_pytest/approx.py:589
return absolute_tolerance
# Figure out what the relative tolerance should be. ``self.rel`` is
# either None or a value specified by the user. This is done after
# we've made sure the user didn't ask for an absolute tolerance only,
# because we don't want to raise errors about the relative tolerance if
# we aren't even going to use it.
rel = self.rel if self.rel is not None else self.DEFAULT_RELATIVE_TOLERANCE
# expected is SupportAbs, checked in __init__.
# The typing here is not exact...
abs_expected: ExpectedT = abs(self.expected) # type: ignore[arg-type]
relative_tolerance: float | Decimal = rel * abs_expected # type: ignore[operator]
if relative_tolerance < 0:
raise ValueError(
f"relative tolerance can't be negative: {relative_tolerance}"
)
if math.isnan(relative_tolerance):
raise ValueError("relative tolerance can't be NaN.")
# Return the larger of the relative and absolute tolerances.
return max(relative_tolerance, absolute_tolerance)
class ApproxDecimal(ApproxScalar[Decimal]):
"""Perform approximate comparisons where the expected value is a Decimal."""
DEFAULT_ABSOLUTE_TOLERANCE = Decimal("1e-12")
DEFAULT_RELATIVE_TOLERANCE = Decimal("1e-6")
rel: Decimal | None
abs: Decimal | None
def __init__(
self,
expected: Decimal,
rel: float | Decimal | timedelta | None,
abs: float | Decimal | timedelta | None,View on GitHub (pinned to 98b357f69e)
Solutions
- If NaN is a valid expected value, pass nan_ok=True: approx(float('nan'), nan_ok=True).
- Ensure the expected value is a finite number before passing it to approx().
- Sanitize rel so it is never NaN.
Example fix
// before
assert v == approx(float('nan'))
// after
assert v == approx(float('nan'), nan_ok=True) Defensive patterns
Strategy: validation
Validate before calling
import math
def safe_approx(x, rel=None, abs=None, nan_ok=False):
if isinstance(x, float) and math.isnan(x) and not nan_ok:
# compare NaN explicitly rather than via approx
return _NaNApprox()
if rel is not None and (isinstance(rel, float) and math.isnan(rel)):
raise ValueError('rel is NaN')
return pytest.approx(x, rel=rel, abs=abs, nan_ok=nan_ok)
class _NaNApprox:
def __eq__(self, other): return isinstance(other, float) and math.isnan(other)\n def __repr__(self): return 'approx(nan)' Type guard
import math
def may_contain_nan(value) -> bool:
try:
return math.isnan(value)
except TypeError:
return False Try / catch
try:
assert v == pytest.approx(expected)
except ValueError as e:
if 'NaN' in str(e) and math.isnan(expected):
assert math.isnan(v)
else:
raise Prevention
- Decide up front whether NaN is a legitimate expected value; if so, pass nan_ok=True.
- Filter NaNs out of source data before deriving expected values or tolerances.
When it happens
Trigger: Call pytest.approx(float('nan')) and compare; or pass rel=float('nan'). Either makes rel*abs(expected) NaN and trips this check.
Common situations: Comparing a value that may legitimately be NaN without setting nan_ok=True; expected value read from a CSV/array that contains NaN; rel tolerance derived from a NaN-containing computation.
Related errors
- absolute tolerance can't be NaN.
- relative tolerance can't be negative: {relative_tolerance}
- absolute tolerance can't be negative: {abs}
- relative tolerance can't be negative: {rel}
- relative tolerance can't be infinite.
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/e10b63e3e0116544.json.
Report an issue: GitHub.