{"record":{"id":"8881c898e394216a","repo":"python/cpython","slug":"cannot-round-a-nan","errorCode":null,"errorMessage":"cannot round a NaN","messagePattern":"cannot round a NaN","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydecimal.py","lineNumber":1844,"sourceCode":"        Decimal('1E+2')\n        >>> with localcontext(ExtendedContext):\n        ...     round(Decimal('-Infinity'), 37)\n        ...     round(Decimal('sNaN123'), 0)\n        Decimal('NaN')\n        Decimal('NaN123')\n\n        \"\"\"\n        if n is not None:\n            # two-argument form: use the equivalent quantize call\n            if not isinstance(n, int):\n                raise TypeError('Second argument to round should be integral')\n            exp = _dec_from_triple(0, '1', -n)\n            return self.quantize(exp)\n\n        # one-argument form\n        if self._is_special:\n            if self.is_nan():\n                raise ValueError(\"cannot round a NaN\")\n            else:\n                raise OverflowError(\"cannot round an infinity\")\n        return int(self._rescale(0, ROUND_HALF_EVEN))\n\n    def __floor__(self):\n        \"\"\"Return the floor of self, as an integer.\n\n        For a finite Decimal instance self, return the greatest\n        integer n such that n <= self.  If self is infinite or a NaN\n        then a Python exception is raised.\n\n        \"\"\"\n        if self._is_special:\n            if self.is_nan():\n                raise ValueError(\"cannot round a NaN\")\n            else:\n                raise OverflowError(\"cannot round an infinity\")\n        return int(self._rescale(0, ROUND_FLOOR))","sourceCodeStart":1826,"sourceCodeEnd":1862,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pydecimal.py#L1826-L1862","documentation":"round(Decimal('NaN')) — the one-argument form — raises ValueError('cannot round a NaN') because there is no nearest integer to a NaN. The two-argument form instead delegates to quantize, which returns NaN under signal-based semantics, so only the one-arg form raises here.","triggerScenarios":"round(Decimal('NaN')); round(Decimal('sNaN')); round(d) where d parsed from 'NaN' text in data.","commonSituations":"Display formatting that rounds values for output, hit by NaN sentinels from data feeds; round(x) used as a quick 'nearest int' on mixed-quality data.","solutions":["Guard with value.is_nan() before rounding; render 'NaN' literally or substitute a policy value","Filter non-finite values upstream of formatting code","In the two-argument form round(d, n) NaN propagates instead — choose the form matching your error strategy"],"exampleFix":"// before\nshown = round(v)  # ValueError when v is NaN\n\n// after\nshown = 'NaN' if v.is_nan() else round(v)","handlingStrategy":"validation","validationCode":"def safe_round1(d):\n    if d.is_nan():\n        raise ValueError(f'cannot round NaN {d}')\n    return round(d)","typeGuard":"def is_roundable(d) -> bool:\n    return not d._is_special","tryCatchPattern":"try:\n    n = round(d)\nexcept ValueError:\n    n = 0  # NaN policy\nexcept OverflowError:\n    raise OverflowError(f'cannot round {d}') from None","preventionTips":["Guard all one-arg round()/int()/floor()/ceil() calls with a single _is_special check","Filter NaN sentinels at ingestion before formatting code","Note the two-arg round(d, n) propagates NaN instead of raising — pick deliberately"],"tags":["decimal","rounding","round","nan","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}