{"record":{"id":"be9be101889764ff","repo":"pytest-dev/pytest","slug":"absolute-tolerance-can-t-be-negative-abs","errorCode":null,"errorMessage":"absolute tolerance can't be negative: {abs}","messagePattern":"absolute tolerance can't be negative: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":669,"sourceCode":"        if nan_ok:\n            raise TypeError(\n                \"pytest.approx() does not support nan_ok for \"\n                \"datetime/timedelta comparisons.\"\n            )\n        if abs is None and rel is None:\n            raise TypeError(\n                \"pytest.approx() requires an explicit tolerance for \"\n                \"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:","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/approx.py#L651-L687","documentation":"Raised by ApproxTimedelta.__init__ when abs is a timedelta but negative. A negative tolerance is meaningless (it would accept nothing or invert the comparison) and almost always indicates a sign mistake. The check runs after confirming abs is a timedelta, so the value can be safely compared to timedelta(0).","triggerScenarios":"approx(td, abs=timedelta(seconds=-1)); computing abs from a subtraction that can go negative without builtins.abs().","commonSituations":"Tolerance computed as (expected - actual) without wrapping in abs(); off-by-sign bugs in test fixture generation.","solutions":["Ensure the tolerance is non-negative: use builtins.abs(...) on the computation.","Pass an explicit positive timedelta literal.","Review how the tolerance value is derived before passing it to approx()."],"exampleFix":"// before\napprox(td, abs=expected - actual)  # may be negative\n// after\napprox(td, abs=abs(expected - actual))","handlingStrategy":"validation","validationCode":"from datetime import timedelta\ndef nonneg_td(v):\n    if v is not None and v < timedelta(0):\n        raise ValueError('tolerance must be non-negative')\n    return v","typeGuard":"from datetime import timedelta\ndef is_nonneg_timedelta(v) -> bool:\n    return v is None or (isinstance(v, timedelta) and v >= timedelta(0))","tryCatchPattern":null,"preventionTips":["Wrap computed tolerances in builtins.abs().","Validate tolerance sign at fixture construction."],"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"}