{"id":"e10b63e3e0116544","repo":"pytest-dev/pytest","slug":"relative-tolerance-can-t-be-nan","errorCode":null,"errorMessage":"relative tolerance can't be NaN.","messagePattern":"relative tolerance can't be NaN\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":589,"sourceCode":"                return absolute_tolerance\n\n        # Figure out what the relative tolerance should be.  ``self.rel`` is\n        # either None or a value specified by the user.  This is done after\n        # we've made sure the user didn't ask for an absolute tolerance only,\n        # because we don't want to raise errors about the relative tolerance if\n        # we aren't even going to use it.\n        rel = self.rel if self.rel is not None else self.DEFAULT_RELATIVE_TOLERANCE\n        # expected is SupportAbs, checked in __init__.\n        # The typing here is not exact...\n        abs_expected: ExpectedT = abs(self.expected)  # type: ignore[arg-type]\n        relative_tolerance: float | Decimal = rel * abs_expected  # type: ignore[operator]\n\n        if relative_tolerance < 0:\n            raise ValueError(\n                f\"relative tolerance can't be negative: {relative_tolerance}\"\n            )\n        if math.isnan(relative_tolerance):\n            raise ValueError(\"relative tolerance can't be NaN.\")\n\n        # Return the larger of the relative and absolute tolerances.\n        return max(relative_tolerance, absolute_tolerance)\n\n\nclass ApproxDecimal(ApproxScalar[Decimal]):\n    \"\"\"Perform approximate comparisons where the expected value is a Decimal.\"\"\"\n\n    DEFAULT_ABSOLUTE_TOLERANCE = Decimal(\"1e-12\")\n    DEFAULT_RELATIVE_TOLERANCE = Decimal(\"1e-6\")\n    rel: Decimal | None\n    abs: Decimal | None\n\n    def __init__(\n        self,\n        expected: Decimal,\n        rel: float | Decimal | timedelta | None,\n        abs: float | Decimal | timedelta | None,","sourceCodeStart":571,"sourceCodeEnd":607,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/approx.py#L571-L607","documentation":"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.","triggerScenarios":"Call pytest.approx(float('nan')) and compare; or pass rel=float('nan'). Either makes rel*abs(expected) NaN and trips this check.","commonSituations":"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.","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."],"exampleFix":"// before\nassert v == approx(float('nan'))\n// after\nassert v == approx(float('nan'), nan_ok=True)","handlingStrategy":"validation","validationCode":"import math\n\ndef safe_approx(x, rel=None, abs=None, nan_ok=False):\n    if isinstance(x, float) and math.isnan(x) and not nan_ok:\n        # compare NaN explicitly rather than via approx\n        return _NaNApprox()\n    if rel is not None and (isinstance(rel, float) and math.isnan(rel)):\n        raise ValueError('rel is NaN')\n    return pytest.approx(x, rel=rel, abs=abs, nan_ok=nan_ok)\n\nclass _NaNApprox:\n    def __eq__(self, other): return isinstance(other, float) and math.isnan(other)\\n    def __repr__(self): return 'approx(nan)'","typeGuard":"import math\n\ndef may_contain_nan(value) -> bool:\n    try:\n        return math.isnan(value)\n    except TypeError:\n        return False","tryCatchPattern":"try:\n    assert v == pytest.approx(expected)\nexcept ValueError as e:\n    if 'NaN' in str(e) and math.isnan(expected):\n        assert math.isnan(v)\n    else:\n        raise","preventionTips":["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."],"tags":["pytest","approx","nan","validation"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}