{"record":{"id":"f1206e518f264809","repo":"pytest-dev/pytest","slug":"relative-tolerance-can-t-be-negative-relative-to","errorCode":null,"errorMessage":"relative tolerance can't be negative: {relative_tolerance}","messagePattern":"relative tolerance can't be negative: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":585,"sourceCode":"        # If the user specified an absolute tolerance but not a relative one,\n        # just return the absolute tolerance.\n        if self.rel is None:\n            if self.abs is not None:\n                return absolute_tolerance\n\n        # Figure out what the relative tolerance should be.  ``self.rel`` is\n        # either None or a value specified by the user.  This is done after\n        # we've made sure the user didn't ask for an absolute tolerance only,\n        # because we don't want to raise errors about the relative tolerance if\n        # we aren't even going to use it.\n        rel = self.rel if self.rel is not None else self.DEFAULT_RELATIVE_TOLERANCE\n        # expected is SupportAbs, checked in __init__.\n        # The typing here is not exact...\n        abs_expected: ExpectedT = abs(self.expected)  # type: ignore[arg-type]\n        relative_tolerance: float | Decimal = rel * abs_expected  # type: ignore[operator]\n\n        if relative_tolerance < 0:\n            raise ValueError(\n                f\"relative tolerance can't be negative: {relative_tolerance}\"\n            )\n        if math.isnan(relative_tolerance):\n            raise ValueError(\"relative tolerance can't be NaN.\")\n\n        # Return the larger of the relative and absolute tolerances.\n        return max(relative_tolerance, absolute_tolerance)\n\n\nclass ApproxDecimal(ApproxScalar[Decimal]):\n    \"\"\"Perform approximate comparisons where the expected value is a Decimal.\"\"\"\n\n    DEFAULT_ABSOLUTE_TOLERANCE = Decimal(\"1e-12\")\n    DEFAULT_RELATIVE_TOLERANCE = Decimal(\"1e-6\")\n    rel: Decimal | None\n    abs: Decimal | None\n\n    def __init__(","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/approx.py#L567-L603","documentation":"In ApproxScalar.tolerance, after computing relative_tolerance = rel * abs(expected), pytest rejects a negative result. This typically means rel itself was negative, since abs(expected) is non-negative for normal numbers. A negative relative tolerance is meaningless and would break the max() selection logic, so it is rejected with the computed value reported.","triggerScenarios":"Calling approx(1.0, rel=-0.01); rel read from config with a stray minus sign; rel computed as a difference that went negative. Triggered at ApproxScalar.tolerance (src/_pytest/approx.py:584-587).","commonSituations":"Tolerance arithmetic producing negative values; sign errors in parameterized tests; mis-typed negative literal.","solutions":["Use a positive relative tolerance: `approx(1.0, rel=0.01)`.","Validate rel before passing: `assert 0 <= rel <= 1`.","If rel is computed, take abs(rel) once the sign error is fixed upstream."],"exampleFix":"# before\napprox(value, rel=-0.01)\n# after\napprox(value, rel=0.01)","handlingStrategy":"validation","validationCode":"def is_nonneg_rel(rel) -> bool:\n    return rel is None or (isinstance(rel, (int, float)) and rel >= 0)\n# usage\nif not is_nonneg_rel(rel):\n    raise ValueError(f'rel must be >= 0, got {rel}')\nassert actual == approx(expected, rel=rel)","typeGuard":"def is_nonneg_float(v) -> bool:\n    return isinstance(v, (int, float)) and v >= 0","tryCatchPattern":null,"preventionTips":["Validate 0 <= rel before constructing approx.","Audit sign errors in computed tolerances.","Add asserts in parameterized tests that rel stays in [0, 1]."],"tags":["pytest","approx","tolerance","value-validation","relative"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}