python/cpython · error · TypeError

integer argument expected, got float

Error message

integer argument expected, got float

What it means

Raised by FileIO.__init__ when the file argument is a float. Because bool is a subclass of int and floats are not accepted as file descriptors, the constructor explicitly rejects float before the int fd handling path (note the bool special case that only draws a RuntimeWarning, whereas float is a hard TypeError).

Source

Thrown at Lib/_pyio.py:1546

        writing.

        A custom opener can be used by passing a callable as *opener*.
        The underlying file descriptor for the file object is then obtained
        by calling opener with (*name*, *flags*).  *opener* must return
        an open file descriptor (passing os.open as *opener* results in
        functionality similar to passing None).
        """
        if self._fd >= 0:
            # Have to close the existing file first.
            self._stat_atopen = None
            try:
                if self._closefd:
                    os.close(self._fd)
            finally:
                self._fd = -1

        if isinstance(file, float):
            raise TypeError('integer argument expected, got float')
        if isinstance(file, int):
            if isinstance(file, bool):
                import warnings
                warnings.warn("bool is used as a file descriptor",
                              RuntimeWarning, stacklevel=2)
                file = int(file)
            fd = file
            if fd < 0:
                raise ValueError('negative file descriptor')
        else:
            fd = -1

        if not isinstance(mode, str):
            raise TypeError('invalid mode: %s' % (mode,))
        if not set(mode) <= set('xrwab+'):
            raise ValueError('invalid mode: %s' % (mode,))
        if sum(c in 'rwax' for c in mode) != 1 or mode.count('+') > 1:
            raise ValueError('Must have exactly one of create/read/write/append '

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass an int file descriptor or a str/bytes/os.PathLike path, never a float
  2. Coerce numeric config values before use: fd = int(fd) after verifying it is integral
  3. If the value is really a path, make sure it stays a string (check for accidental str(fd) vs fd mix-ups)

Example fix

# before
fd = json_config['fd']  # arrived as 3.0
f = open(fd, 'rb')  # TypeError: integer argument expected, got float

# after
fd = int(json_config['fd'])
f = open(fd, 'rb')
Defensive patterns

Strategy: type-guard

Validate before calling

import numbers
def normalize_fd(file):
    if isinstance(file, float):
        if file.is_integer():
            return int(file)
        raise TypeError('integer argument expected, got float')
    return file
f = open(normalize_fd(file_arg), 'rb')

Type guard

def is_fd_or_path(f):
    return isinstance(f, (str, bytes, os.PathLike)) or (isinstance(f, int) and not isinstance(f, (bool, float)) and f >= 0)

Try / catch

try:
    f = open(file_arg, 'rb')
except TypeError as e:
    if 'float' in str(e):
        f = open(int(file_arg), 'rb')
    else:
        raise

Prevention

When it happens

Trigger: open(3.0, 'rb') or io.FileIO(2.5); passing a value computed with float arithmetic (e.g. os.dup results passed through float(), or division like fd/1) where a file descriptor integer or a path was expected.

Common situations: fd variables accidentally converted to float by numeric pipelines (numpy scalars of dtype float are also rejected differently, but plain Python float hits this exact branch); typos where a path string was replaced by a numeric variable; JSON-parsed config in which the fd arrived as 3.0 instead of 3.

Related errors


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