{"record":{"id":"2ab03953714e4de6","repo":"python/cpython","slug":"cannot-convert-signaling-nan-to-float","errorCode":null,"errorMessage":"Cannot convert signaling NaN to float","messagePattern":"Cannot convert signaling NaN to float","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydecimal.py","lineNumber":1570,"sourceCode":"                return context._raise_error(DivisionByZero, 'x // 0',\n                                            self._sign ^ other._sign)\n            else:\n                return context._raise_error(DivisionUndefined, '0 // 0')\n\n        return self._divide(other, context)[0]\n\n    def __rfloordiv__(self, other, context=None):\n        \"\"\"Swaps self/other and returns __floordiv__.\"\"\"\n        other = _convert_other(other)\n        if other is NotImplemented:\n            return other\n        return other.__floordiv__(self, context=context)\n\n    def __float__(self):\n        \"\"\"Float representation.\"\"\"\n        if self._isnan():\n            if self.is_snan():\n                raise ValueError(\"Cannot convert signaling NaN to float\")\n            s = \"-nan\" if self._sign else \"nan\"\n        else:\n            s = str(self)\n        return float(s)\n\n    def __int__(self):\n        \"\"\"Converts self to an int, truncating if necessary.\"\"\"\n        if self._is_special:\n            if self._isnan():\n                raise ValueError(\"Cannot convert NaN to integer\")\n            elif self._isinfinity():\n                raise OverflowError(\"Cannot convert infinity to integer\")\n        s = (-1)**self._sign\n        if self._exp >= 0:\n            return s*int(self._int)*10**self._exp\n        else:\n            return s*int(self._int[:self._exp] or '0')\n","sourceCodeStart":1552,"sourceCodeEnd":1588,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pydecimal.py#L1552-L1588","documentation":"float(Decimal('sNaN')) raises ValueError because a signaling NaN must trap on use, and conversion to float counts as a use; converting it would silently demote it to a quiet float NaN and lose the signal. Quiet NaNs convert fine to float('nan') with sign preserved.","triggerScenarios":"float(Decimal('sNaN')); float(Decimal('sNaN123')); math.sin(Decimal('sNaN')) (implicit float conversion); json serialization code that calls float() on values.","commonSituations":"Parsed FIX/financial data carrying sNaN sentinels, then passed to float-based APIs (math, numpy, json); mixing decimal strictness with float-land helpers.","solutions":["Quiet the sNaN first if loss of signal is acceptable: q = d + 0 under a context with InvalidOperation untrapped yields quiet NaN, then float(q)","Reject sNaN explicitly at the boundary with is_snan() and raise your own error","Keep the pipeline in Decimal end-to-end so no float() conversion is needed"],"exampleFix":"// before\nf = float(dec)  # ValueError if dec is Decimal('sNaN')\n\n// after\nimport math\nf = math.nan if dec.is_snan() else float(dec)","handlingStrategy":"validation","validationCode":"import math\n\ndef safe_float(d):\n    if d.is_snan():\n        return math.nan  # explicit policy: quiet it\n    return float(d)","typeGuard":"from decimal import Decimal\n\ndef is_float_safe(d) -> bool:\n    return not (isinstance(d, Decimal) and d.is_snan())","tryCatchPattern":"try:\n    f = float(d)\nexcept ValueError as e:\n    if 'signaling NaN' in str(e):\n        f = float('nan')\n    else:\n        raise","preventionTips":["Quieten sNaN immediately after parsing (d * 1 under a non-trapping context)","Keep numeric pipelines in Decimal until the final boundary; convert once, guarded","Distinguish is_snan() from is_nan() in validation: quiet NaN converts fine"],"tags":["decimal","float-conversion","snan","nan","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}