{"id":"ab29b7d30b2db9ce","repo":"pytest-dev/pytest","slug":"relative-tolerance-can-t-be-negative-rel","errorCode":null,"errorMessage":"relative tolerance can't be negative: {rel}","messagePattern":"relative tolerance can't be negative: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":677,"sourceCode":"                \"datetime/timedelta comparisons: \"\n                \"e.g. approx(expected, abs=timedelta(seconds=1)) \"\n                \"or approx(expected, rel=0.01)\"\n            )\n        if abs is not None and not isinstance(abs, timedelta):\n            raise TypeError(\n                f\"absolute tolerance for datetime/timedelta must be a \"\n                f\"timedelta, got {type(abs).__name__}\"\n            )\n        if abs is not None and abs < timedelta(0):\n            raise ValueError(f\"absolute tolerance can't be negative: {abs}\")\n        if rel is not None:\n            if not isinstance(rel, (int, float)):\n                raise TypeError(\n                    f\"relative tolerance for timedelta must be a \"\n                    f\"number, got {type(rel).__name__}\"\n                )\n            if rel < 0:\n                raise ValueError(f\"relative tolerance can't be negative: {rel}\")\n            if math.isnan(rel):\n                raise ValueError(\"relative tolerance can't be NaN.\")\n            if math.isinf(rel):\n                raise ValueError(\"relative tolerance can't be infinite.\")\n        # Compute the effective tolerance. abs_tolerance is a timedelta, rel * expected\n        # gives a timedelta (timedelta * float works in Python).\n        abs_tolerance = abs\n        if rel is None:\n            rel_tolerance = None\n        else:\n            # Checked above.\n            assert not isinstance(expected, datetime)\n            rel_tolerance = rel * builtins.abs(expected)\n        if abs_tolerance is not None and rel_tolerance is not None:\n            tolerance: timedelta | None = max(abs_tolerance, rel_tolerance)\n        else:\n            tolerance = abs_tolerance if abs_tolerance is not None else rel_tolerance\n        super().__init__(expected, rel=rel, abs=tolerance, nan_ok=False)","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/approx.py#L659-L695","documentation":"ApproxTimedelta.__init__ rejects a negative relative tolerance for timedelta comparisons. A negative fraction of the expected duration is not a meaningful tolerance.","triggerScenarios":"Call pytest.approx(some_timedelta, rel=-0.01) (or any negative numeric rel).","commonSituations":"Sign error when copying a tolerance; tolerance derived from a computation that can go negative; config typo.","solutions":["Use a non-negative rel: approx(td, rel=0.01).","Validate the source of the value and strip the sign.","Clamp or assert in the producing fixture."],"exampleFix":"// before\nassert got == approx(td, rel=-0.01)\n// after\nassert got == approx(td, rel=0.01)","handlingStrategy":"validation","validationCode":"def approx_td_rel(value, rel):\n    if not isinstance(rel, (int, float)) or rel < 0:\n        raise ValueError(f'rel must be a non-negative number, got {rel!r}')\n    return pytest.approx(value, rel=rel)","typeGuard":"def is_nonneg_number(v) -> bool:\n    return isinstance(v, (int, float)) and v >= 0","tryCatchPattern":null,"preventionTips":["Validate tolerance signs at config/fixture load time.","Add unit tests covering negative inputs to your tolerance helpers."],"tags":["pytest","approx","timedelta","validation"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}