pytest-dev/pytest · error · TypeError
expected value must support abs(...) when relative tolerance
Error message
expected value must support abs(...) when relative tolerance is used, got {type(expected).__name__} What it means
When a relative tolerance (rel) is specified for ApproxScalar, the expected value must support abs(...) to compute the relative component (rel * abs(expected)). If the expected value does not implement __abs__ (e.g., a string or custom object), pytest raises TypeError. This is validated eagerly in __init__.
Source
Thrown at src/_pytest/approx.py:455
rel: float | Decimal | None
abs: float | Decimal | None
def __init__(
self,
expected: ExpectedT,
rel: float | Decimal | timedelta | None,
abs: float | Decimal | timedelta | None,
nan_ok: bool,
) -> None:
__tracebackhide__ = True
if rel is not None:
if not isinstance(rel, (int, float, Decimal)):
raise TypeError(
f"relative tolerance for a scalar value must be an int, float or Decimal, "
f"got {type(rel).__name__}"
)
if not isinstance(expected, SupportsAbs):
raise TypeError(
f"expected value must support abs(...) when relative tolerance is used, "
f"got {type(expected).__name__}"
)
if abs is not None and not isinstance(abs, (int, float, Decimal)):
raise TypeError(
f"absolute tolerance for a scalar value must be an int, float or Decimal, "
f"got {type(abs).__name__}"
)
super().__init__(expected, rel=rel, abs=abs, nan_ok=nan_ok)
def __repr__(self) -> str:
"""Return a string communicating both the expected value and the
tolerance for the comparison being made.
For example, ``1.0 ± 1e-6``, ``(3+4j) ± 5e-6 ∠ ±180°``.
"""
# Don't show a tolerance for values that aren't compared using
# tolerances, i.e. non-numerics and infinities. Need to call abs toView on GitHub (pinned to 98b357f69e)
Solutions
- Use absolute tolerance (abs=) instead of relative tolerance for non-numeric or non-abs-supporting values.
- Remove the rel parameter if only exact comparison is needed.
- Ensure the expected value is numeric (int, float, Decimal) when using rel.
Example fix
# before
approx('hello', rel=0.01)
# after
approx('hello') # no rel, exact comparison
# or for numeric values:
approx(3.14, rel=0.01) Defensive patterns
Strategy: type-guard
Validate before calling
from typing import Protocol
import numbers
class SupportsAbs(Protocol):
def __abs__(self) -> float: ...
def validate_expected_with_rel(expected, rel):
if rel is not None and not hasattr(expected, '__abs__'):
raise TypeError(f'expected value must support abs() when rel is used, got {type(expected).__name__}')
return expected
# usage:
# if rel_tol: validate_expected_with_rel(value, rel_tol) Type guard
def supports_abs(value) -> bool:
return hasattr(value, '__abs__') and callable(getattr(value, '__abs__')) Prevention
- Only use rel= with numeric expected values (int, float, Decimal, complex).
- For non-numeric comparisons, use abs= or omit tolerance entirely.
- Check that the expected value is a number before applying relative tolerance.
When it happens
Trigger: Calling approx('hello', rel=0.01) or approx(SomeObj(), rel=0.01) where the expected value lacks __abs__. The isinstance(expected, SupportsAbs) check fails.
Common situations: Comparing a non-numeric value with a relative tolerance, or passing a tolerance meant for numbers to a custom object comparison.
Related errors
- relative tolerance for a scalar value must be an int, float
- absolute tolerance for a scalar value must be an int, float
- absolute tolerance can't be negative: {absolute_tolerance}
- cannot compare '{actual}' to numpy.ndarray
- pytest.approx() does not support nested dictionaries: key={!
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/af23743444ccb4f2.json.
Report an issue: GitHub.