{"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/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/approx.py#L654-L690","documentation":"ApproxTimedelta.__init__ requires the relative tolerance for a timedelta comparison to be a number (int or float), because rel is multiplied by abs(expected) (a timedelta) to produce a timedelta tolerance. Non-numeric rel values cannot be multiplied.","triggerScenarios":"Call pytest.approx(some_timedelta, rel='0.01') or rel=timedelta(...) — any non-int/float value for rel when expected is a timedelta.","commonSituations":"Reading rel from a config file as a string; accidentally passing a timedelta as rel instead of abs; copy-paste errors.","solutions":["Pass rel as a float: approx(td, rel=0.01).","If you have a string tolerance, cast it: rel=float(my_str).","Use abs=timedelta(...) instead if you actually have a duration tolerance."],"exampleFix":"// before\nassert got == approx(td, rel='0.01')\n// after\nassert got == approx(td, rel=0.01)","handlingStrategy":"type-guard","validationCode":"def approx_td_rel(value, rel):\n    if not isinstance(rel, (int, float)):\n        raise TypeError(f'rel must be a number, got {type(rel).__name__}')\n    return pytest.approx(value, rel=rel)","typeGuard":"def is_number(v) -> bool:\n    return isinstance(v, (int, float)) and not isinstance(v, bool)","tryCatchPattern":null,"preventionTips":["Cast string tolerances with float() at the config boundary.","Keep abs=timedelta and rel=float distinct in your helpers; do not let callers swap them."],"tags":["pytest","approx","timedelta","type-mismatch"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}