pytest-dev/pytest · error · ValueError
relative tolerance can't be negative
Error message
relative tolerance can't be negative: {rel} What it means
Raised by ApproxTimedelta.__init__ when rel is numeric but negative. A negative relative tolerance is meaningless; this almost always indicates a sign error or a bad computation. The check occurs after type validation, before NaN/inf checks.
Solutions
- Use a non-negative rel value: rel=0.01.
- Wrap computations in builtins.abs() to avoid sign flips.
- Validate tolerance inputs at test-fixture build time.
Example fix
// before approx(td, rel=-0.01) // after approx(td, rel=0.01)
Defensive patterns
Strategy: validation
Validate before calling
def clamp_rel(rel):
if rel is not None and rel < 0:
raise ValueError('rel must be >= 0')
return rel Type guard
def is_nonneg_number(v) -> bool:
return v is None or (isinstance(v, (int, float)) and v >= 0) Prevention
- Use non-negative rel literals.
- Guard computed ratios with builtins.abs().
When it happens
Trigger: approx(td, rel=-0.01); passing a computed ratio that went negative.
Common situations: Tolerance ratios derived from differences without abs(); copy-paste errors in parametrized tolerance values.
Related errors
- absolute tolerance can't be negative
- relative tolerance can't be infinite.
- absolute tolerance for datetime/timedelta must be a…
- relative tolerance for timedelta must be a number, got
- absolute tolerance can't be NaN.
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/ab29b7d30b2db9ce.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/approx.py:677
"datetime/timedelta comparisons: "
"e.g. approx(expected, abs=timedelta(seconds=1)) "
"or approx(expected, rel=0.01)"
)
if abs is not None and not isinstance(abs, timedelta):
raise TypeError(
f"absolute tolerance for datetime/timedelta must be a "
f"timedelta, got {type(abs).__name__}"
)
if abs is not None and abs < timedelta(0):
raise ValueError(f"absolute tolerance can't be negative: {abs}")
if rel is not None:
if not isinstance(rel, (int, float)):
raise TypeError(
f"relative tolerance for timedelta must be a "
f"number, got {type(rel).__name__}"
)
if rel < 0:
raise ValueError(f"relative tolerance can't be negative: {rel}")
if math.isnan(rel):
raise ValueError("relative tolerance can't be NaN.")
if math.isinf(rel):
raise ValueError("relative tolerance can't be infinite.")
# Compute the effective tolerance. abs_tolerance is a timedelta, rel * expected
# gives a timedelta (timedelta * float works in Python).
abs_tolerance = abs
if rel is None:
rel_tolerance = None
else:
# Checked above.
assert not isinstance(expected, datetime)
rel_tolerance = rel * builtins.abs(expected)
if abs_tolerance is not None and rel_tolerance is not None:
tolerance: timedelta | None = max(abs_tolerance, rel_tolerance)
else:
tolerance = abs_tolerance if abs_tolerance is not None else rel_tolerance
super().__init__(expected, rel=rel, abs=tolerance, nan_ok=False)View on GitHub (pinned to 0d6fbdeffa)