boto/boto3 · error · ValueError

Fileobj must implement write

Error message

Fileobj must implement write

What it means

Raised by the injected download_fileobj() helper when the destination Fileobj argument lacks a 'write' attribute. download_fileobj writes the downloaded bytes into a file-like object via the managed transfer manager, so the target must implement write() accepting bytes. Anything that cannot receive binary writes is rejected up front with this ValueError.

Source

Thrown at boto3/s3/inject.py:841

    :type Fileobj: a file-like object
    :param Fileobj: A file-like object to download into. At a minimum, it must
        implement the `write` method and must accept bytes.

    :type ExtraArgs: dict
    :param ExtraArgs: Extra arguments that may be passed to the
        client operation. For allowed download arguments see
        :py:attr:`boto3.s3.transfer.S3Transfer.ALLOWED_DOWNLOAD_ARGS`.

    :type Callback: function
    :param Callback: A method which takes a number of bytes transferred to
        be periodically called during the download.

    :type Config: boto3.s3.transfer.TransferConfig
    :param Config: The transfer configuration to be used when performing the
        download.
    """
    if not hasattr(Fileobj, 'write'):
        raise ValueError('Fileobj must implement write')

    subscribers = None
    if Callback is not None:
        subscribers = [ProgressCallbackInvoker(Callback)]

    config = Config
    if config is None:
        config = TransferConfig()

    new_config = python_copy.copy(config)
    disable_threading_if_append_mode(new_config, Fileobj)

    with create_transfer_manager(self, new_config) as manager:
        future = manager.download(
            bucket=Bucket,
            key=Key,
            fileobj=Fileobj,
            extra_args=ExtraArgs,

View on GitHub (pinned to c7b4afac23)

Solutions

  1. Pass an open writable binary handle: with open(path, 'wb') as f: s3.download_fileobj(bucket, key, f).
  2. If you want to download straight to a path, use s3.download_file(bucket, key, filename) instead.
  3. For in-memory downloads, target io.BytesIO() and call getvalue() afterwards.
  4. Confirm the handle is not opened in read or text mode.

Example fix

// before
with open('out.txt', 'r') as f:
    s3.download_fileobj('mybucket', 'key', f)  # wrong: not writable

// after
with open('out.txt', 'wb') as f:
    s3.download_fileobj('mybucket', 'key', f)
Defensive patterns

Strategy: type-guard

Validate before calling

if not hasattr(fileobj, 'write'):
    raise TypeError('download_fileobj requires a writable file-like object')
s3.download_fileobj(bucket, key, fileobj)

Type guard

def is_writable_fileobj(obj) -> bool:
    return hasattr(obj, 'write') and callable(getattr(obj, 'write'))

Try / catch

try:
    s3.download_fileobj(bucket, key, fileobj)
except ValueError as e:
    if 'must implement write' in str(e):
        with open(path, 'wb') as f:
            s3.download_fileobj(bucket, key, f)

Prevention

When it happens

Trigger: Calling s3.download_fileobj(Bucket, Key, Fileobj) / bucket.download_fileobj(Key, Fileobj) where Fileobj is a filename string (use download_file instead), a file opened in read mode ('r'/'rb'), a bytes object, a StringIO, None, or any object without a write method.

Common situations: Confusing download_file (takes a filename) with download_fileobj (takes an open writable file); opening the target file with open(path, 'r') instead of 'wb'; passing a string path; reusing a read handle as the download target.

Related errors


AI-assisted analysis of boto/boto3@c7b4afac23 (2026-08-04). Data as JSON: /data/errors/cb87edc34bdcb3a1.json. Report an issue: GitHub.