{"record":{"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/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/approx.py#L659-L695","documentation":"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.","triggerScenarios":"approx(td, rel=-0.01); passing a computed ratio that went negative.","commonSituations":"Tolerance ratios derived from differences without abs(); copy-paste errors in parametrized tolerance values.","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."],"exampleFix":"// before\napprox(td, rel=-0.01)\n// after\napprox(td, rel=0.01)","handlingStrategy":"validation","validationCode":"def clamp_rel(rel):\n    if rel is not None and rel < 0:\n        raise ValueError('rel must be >= 0')\n    return rel","typeGuard":"def is_nonneg_number(v) -> bool:\n    return v is None or (isinstance(v, (int, float)) and v >= 0)","tryCatchPattern":null,"preventionTips":["Use non-negative rel literals.","Guard computed ratios with builtins.abs()."],"tags":["approx","timedelta","validation","value-error"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}