boto/boto3 · error · ValueError

Fileobj must implement read

Error message

Fileobj must implement read

What it means

Raised by the injected upload_fileobj() helper (on the S3 client, Bucket, and Object resources) when the Fileobj argument lacks a 'read' attribute. upload_fileobj streams bytes from a file-like object to S3 via the managed transfer manager, and it requires an object that implements read() returning bytes. Passing anything that is not a readable binary stream is rejected up front with this ValueError.

Source

Thrown at boto3/s3/inject.py:660

    :type Key: str
    :param Key: The name of the key to upload to.

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

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

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

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

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

    with create_transfer_manager(self, config) as manager:
        future = manager.upload(
            fileobj=Fileobj,
            bucket=Bucket,
            key=Key,
            extra_args=ExtraArgs,
            subscribers=subscribers,
        )
        return future.result()

View on GitHub (pinned to c7b4afac23)

Solutions

  1. Pass an already-opened binary file handle: with open(path, 'rb') as f: s3.upload_fileobj(f, bucket, key).
  2. If you only have a filename/path, use s3.upload_file(filename, bucket, key) instead of upload_fileobj.
  3. If you have an in-memory bytes payload, wrap it with io.BytesIO(data) before calling upload_fileobj.
  4. Ensure you are not passing a text-mode handle or a string.

Example fix

// before
s3.upload_fileobj('data.txt', 'mybucket', 'key')  # wrong: string, not file-like

// after
with open('data.txt', 'rb') as f:
    s3.upload_fileobj(f, 'mybucket', 'key')
Defensive patterns

Strategy: type-guard

Validate before calling

if not hasattr(fileobj, 'read'):
    raise TypeError('upload_fileobj requires a readable file-like object')
s3.upload_fileobj(fileobj, bucket, key)

Type guard

def is_readable_fileobj(obj) -> bool:
    return hasattr(obj, 'read') and callable(getattr(obj, 'read'))

Try / catch

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

Prevention

When it happens

Trigger: Calling s3.upload_fileobj(Fileobj, Bucket, Key) / bucket.upload_fileobj(...) where Fileobj is a path string (meant for upload_file instead), a bytes object, a file opened in text mode ('r' without 'b'), a StringIO, None, or any object without a read method.

Common situations: Confusing upload_file (takes a filename string) with upload_fileobj (takes an open file); opening the file with open(path) (text mode) and forgetting 'rb'; passing the raw value returned from requests/urllib without wrapping it; passing a pathlib.Path object.

Related errors


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