{"record":{"id":"405375e8bb014fbd","repo":"pytest-dev/pytest","slug":"absolute-tolerance-can-t-be-negative-absolute-to","errorCode":null,"errorMessage":"absolute tolerance can't be negative: {absolute_tolerance}","messagePattern":"absolute tolerance can't be negative: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":561,"sourceCode":"        return result\n\n    __hash__ = None\n\n    @property\n    def tolerance(self):\n        \"\"\"Return the tolerance for the comparison.\n\n        This could be either an absolute tolerance or a relative tolerance,\n        depending on what the user specified or which would be larger.\n        \"\"\"\n        # Figure out what the absolute tolerance should be.  ``self.abs`` is\n        # either None or a value specified by the user.\n        absolute_tolerance = (\n            self.abs if self.abs is not None else self.DEFAULT_ABSOLUTE_TOLERANCE\n        )\n\n        if absolute_tolerance < 0:\n            raise ValueError(\n                f\"absolute tolerance can't be negative: {absolute_tolerance}\"\n            )\n        if math.isnan(absolute_tolerance):\n            raise ValueError(\"absolute tolerance can't be NaN.\")\n\n        # 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__.","sourceCodeStart":543,"sourceCodeEnd":579,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/approx.py#L543-L579","documentation":"The ApproxScalar.tolerance property computes the effective absolute tolerance and rejects negative values because a negative tolerance window makes no geometric sense (no value would ever be 'within' a negative distance of expected). pytest raises ValueError naming the offending value so the user can correct it. This is checked before the NaN check.","triggerScenarios":"Calling approx(1.0, abs=-1e-3); passing abs=float('-1e-3'); abs computed/loaded as negative due to a sign error or subtraction bug. Triggered at ApproxScalar.tolerance (src/_pytest/approx.py:560-563).","commonSituations":"Tolerance read from config where a stray minus sign was introduced; arithmetic on tolerances (abs=a-b) that can go negative; copy-paste errors.","solutions":["Use a positive absolute tolerance: `approx(1.0, abs=1e-3)`.","If computing tolerance dynamically, clamp with `abs(abs_tol, ...)` or `max(abs_tol, 0.0)` after fixing the sign logic.","Validate config-supplied tolerances at load time and fail with a clearer message."],"exampleFix":"# before\napprox(value, abs=-1e-3)\n# after\napprox(value, abs=1e-3)","handlingStrategy":"validation","validationCode":"def is_nonneg_tolerance(t) -> bool:\n    return t is None or (isinstance(t, (int, float)) and t >= 0)\n# usage\nif not is_nonneg_tolerance(abs_tol):\n    raise ValueError(f'absolute tolerance must be >= 0, got {abs_tol}')\nassert actual == approx(expected, abs=abs_tol)","typeGuard":"from decimal import Decimal\ndef is_nonneg_scalar(v) -> bool:\n    return isinstance(v, (int, float, Decimal)) and v >= 0","tryCatchPattern":null,"preventionTips":["Validate abs >= 0 before passing to approx.","Audit sign-producing arithmetic that feeds abs.","Add a config-loader check that rejects negative tolerances."],"tags":["pytest","approx","tolerance","value-validation","scalar"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}