{"id":"f1206e518f264809","repo":"pytest-dev/pytest","slug":"relative-tolerance-can-t-be-negative-relative-to","errorCode":null,"errorMessage":"relative tolerance can't be negative: {relative_tolerance}","messagePattern":"relative tolerance can't be negative: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":585,"sourceCode":"        # If the user specified an absolute tolerance but not a relative one,\n        # just return the absolute tolerance.\n        if self.rel is None:\n            if self.abs is not None:\n                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__(","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/approx.py#L567-L603","documentation":"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.","triggerScenarios":"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.","commonSituations":"Typo or sign error when copying a tolerance; tolerance loaded from config/fixture with a stray minus sign; accidentally negating a value during refactoring.","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."],"exampleFix":"// before\nassert v == approx(1.0, rel=-0.01)\n// after\nassert v == approx(1.0, rel=0.01)","handlingStrategy":"validation","validationCode":"def safe_approx_rel(x, rel_tol):\n    if rel_tol is None:\n        return pytest.approx(x)\n    if not isinstance(rel_tol, (int, float)):\n        raise TypeError(f'rel must be a number, got {type(rel_tol).__name__}')\n    if rel_tol < 0:\n        raise ValueError(f'rel must be >= 0, got {rel_tol}')\n    return pytest.approx(x, rel=rel_tol)","typeGuard":"def is_nonneg_number(v) -> bool:\n    return isinstance(v, (int, float)) and v >= 0","tryCatchPattern":"try:\n    assert v == pytest.approx(1.0, rel=tol)\nexcept ValueError as e:\n    if 'relative tolerance' in str(e):\n        assert v == pytest.approx(1.0, rel=1e-6)\n    else:\n        raise","preventionTips":["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."],"tags":["pytest","approx","validation"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}