python/cpython · error · ValueError

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

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.

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)

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.