{"record":{"id":"a44456c59550bba0","repo":"pytest-dev/pytest","slug":"relative-tolerance-for-timedelta-must-be-a-number","errorCode":null,"errorMessage":"relative tolerance for timedelta must be a number, got {type(rel).__name__}","messagePattern":"relative tolerance for timedelta must be a number, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":672,"sourceCode":"                \"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:\n            # Checked above.\n            assert not isinstance(expected, datetime)\n            rel_tolerance = rel * builtins.abs(expected)","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/approx.py#L654-L690","documentation":"Raised by ApproxTimedelta.__init__ when rel is provided for a timedelta comparison but is not an int or float. Relative tolerance for timedelta is a dimensionless multiplier (e.g. 0.01 = 1%), so non-numeric values are rejected with TypeError naming the offending type.","triggerScenarios":"approx(td, rel=timedelta(seconds=1)); approx(td, rel='0.01'); approx(td, rel=None_str).","commonSituations":"Confusing abs (timedelta) and rel (number) parameter types; passing a string from config into rel.","solutions":["Use abs=timedelta(...) for absolute time tolerance.","Ensure rel is a numeric literal: rel=0.01.","Convert config strings with float() before passing."],"exampleFix":"// before\napprox(td, rel=timedelta(seconds=1))\n// after\napprox(td, abs=timedelta(seconds=1))","handlingStrategy":"type-guard","validationCode":"def approx_td_rel(expected, *, rel=None, **kw):\n    if rel is not None and not isinstance(rel, (int, float)):\n        raise TypeError('rel must be a number')\n    return approx(expected, rel=rel, **kw)","typeGuard":"import numbers\ndef is_number_or_none(v) -> bool:\n    return v is None or isinstance(v, numbers.Real)","tryCatchPattern":null,"preventionTips":["rel is a dimensionless float; abs is a timedelta for time values.","Keep the two parameter types distinct in your test helpers."],"tags":["approx","timedelta","type-mismatch"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}