pytest-dev/pytest · error · ValueError
relative tolerance can't be negative: {relative_tolerance}
Error message
relative tolerance can't be negative: {relative_tolerance} What it means
Raised by ApproxScalar.tolerance when the computed relative tolerance (rel * abs(expected)) is negative. A negative tolerance makes no sense for an approximate-equality check, so pytest rejects it loudly.
Source
Thrown at src/_pytest/approx.py:585
# If the user specified an absolute tolerance but not a relative one,
# just return the absolute tolerance.
if self.rel is None:
if self.abs is not None:
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__(View on GitHub (pinned to 98b357f69e)
Solutions
- Use a non-negative rel value, e.g. rel=0.01.
- Check the source of the rel value (config file, fixture, computed expression) and strip/correct the sign.
- Add an assert rel >= 0 in the fixture producing the tolerance to catch it earlier.
Example fix
// before assert v == approx(1.0, rel=-0.01) // after assert v == approx(1.0, rel=0.01)
Defensive patterns
Strategy: validation
Validate before calling
def safe_approx_rel(x, rel_tol):
if rel_tol is None:
return pytest.approx(x)
if not isinstance(rel_tol, (int, float)):
raise TypeError(f'rel must be a number, got {type(rel_tol).__name__}')
if rel_tol < 0:
raise ValueError(f'rel must be >= 0, got {rel_tol}')
return pytest.approx(x, rel=rel_tol) Type guard
def is_nonneg_number(v) -> bool:
return isinstance(v, (int, float)) and v >= 0 Try / catch
try:
assert v == pytest.approx(1.0, rel=tol)
except ValueError as e:
if 'relative tolerance' in str(e):
assert v == pytest.approx(1.0, rel=1e-6)
else:
raise Prevention
- Load tolerances from typed config (not raw strings) and validate signs at load time.
- Add a unit test for the helper that produces your tolerance values, including the negative-case.
When it happens
Trigger: Call pytest.approx(x, rel=-0.1) or any call where the rel argument is negative; the check fires on the product rel*abs(expected), so a negative rel is the usual cause.
Common situations: Typo or sign error when copying a tolerance; tolerance loaded from config/fixture with a stray minus sign; accidentally negating a value during refactoring.
Related errors
- absolute tolerance can't be NaN.
- relative tolerance can't be NaN.
- 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/f1206e518f264809.json.
Report an issue: GitHub.