python/cpython · error · ValueError

The third value in the tuple must be an integer, or one of…

Error message

The third value in the tuple must be an integer, or one of the strings 'F', 'n', 'N'.

What it means

In Decimal's tuple/list constructor, the third element (exponent) must be an int for finite numbers, or one of the exact strings 'F' (infinity), 'n', 'N' (NaN). Anything else — 'f', 'Inf', None, a float — raises this ValueError. Note the case-sensitivity: only uppercase 'F' means infinity while both 'n' and 'N' mean NaN.

Solutions

  1. Use an int exponent for finite values: Decimal((0, (1, 4), -1))
  2. Use the exact markers: 'F' for infinity, 'n' or 'N' for NaN
  3. If the marker may be arbitrary case, normalize it first: exp = exp.upper() if isinstance(exp, str) else exp, mapping 'INF'->'F', 'NAN'->'n'

Example fix

// before
d = Decimal((0, (1,), marker))  # marker='f' or 'NaN' -> ValueError

// after
MARK = {'f': 'F', 'inf': 'F', 'n': 'n', 'nan': 'n'}
d = Decimal((0, (1,), MARK.get(marker.lower(), marker)))
Defensive patterns

Strategy: validation

Validate before calling

SPECIAL_EXP = ('F', 'n', 'N')

def valid_exp(e):
    return isinstance(e, int) or e in SPECIAL_EXP

# normalize common markers before constructing:
def norm_exp(e):
    if isinstance(e, str):
        return {'f': 'F', 'inf': 'F', 'n': 'n', 'nan': 'n'}.get(e.lower(), e)
    return e

Type guard

def is_valid_third(e) -> bool:
    return isinstance(e, int) or e in ('F', 'n', 'N')

Try / catch

try:
    d = Decimal((sign, digits, exp))
except ValueError as e:
    if 'third value' in str(e):
        d = Decimal((sign, digits, norm_exp(exp)))

Prevention

When it happens

Trigger: Decimal((0, (1,), 'f')) (lowercase f); Decimal((0, (1,), None)); Decimal((0, (1,), 2.0)) (float exponent not int); Decimal((0, (1,), 'inf')).

Common situations: Deserializing triples where special-value markers were lowercased by JSON or a normalizer; replacing the exponent with None for 'no exponent'; copying as_tuple() output of a NaN ((0, (0,), 'n') style) but mutating the marker string.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/114dc6cb61ed4822. Report an issue: GitHub.

Appendix: source

Thrown at Lib/_pydecimal.py:593

                        # skip leading zeros
                        if digits or digit != 0:
                            digits.append(digit)
                    else:
                        raise ValueError("The second value in the tuple must "
                                         "be composed of integers in the range "
                                         "0 through 9.")
                if value[2] in ('n', 'N'):
                    # NaN: digits form the diagnostic
                    self._int = ''.join(map(str, digits))
                    self._exp = value[2]
                    self._is_special = True
                elif isinstance(value[2], int):
                    # finite number: digits give the coefficient
                    self._int = ''.join(map(str, digits or [0]))
                    self._exp = value[2]
                    self._is_special = False
                else:
                    raise ValueError("The third value in the tuple must "
                                     "be an integer, or one of the "
                                     "strings 'F', 'n', 'N'.")
            return self

        if isinstance(value, float):
            if context is None:
                context = getcontext()
            context._raise_error(FloatOperation,
                "strict semantics for mixing floats and Decimals are "
                "enabled")
            value = Decimal.from_float(value)
            self._exp  = value._exp
            self._sign = value._sign
            self._int  = value._int
            self._is_special  = value._is_special
            return self

        raise TypeError("Cannot convert %r to Decimal" % value)

View on GitHub (pinned to bc6749cc3b)