{"record":{"id":"194f6b08dab5d29e","repo":"boto/boto3","slug":"fileobj-must-implement-read","errorCode":null,"errorMessage":"Fileobj must implement read","messagePattern":"Fileobj must implement read","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"boto3/s3/inject.py","lineNumber":660,"sourceCode":"\n    :type Key: str\n    :param Key: The name of the key to upload to.\n\n    :type ExtraArgs: dict\n    :param ExtraArgs: Extra arguments that may be passed to the\n        client operation. For allowed upload arguments see\n        :py:attr:`boto3.s3.transfer.S3Transfer.ALLOWED_UPLOAD_ARGS`.\n\n    :type Callback: function\n    :param Callback: A method which takes a number of bytes transferred to\n        be periodically called during the upload.\n\n    :type Config: boto3.s3.transfer.TransferConfig\n    :param Config: The transfer configuration to be used when performing the\n        upload.\n    \"\"\"\n    if not hasattr(Fileobj, 'read'):\n        raise ValueError('Fileobj must implement read')\n\n    subscribers = None\n    if Callback is not None:\n        subscribers = [ProgressCallbackInvoker(Callback)]\n\n    config = Config\n    if config is None:\n        config = TransferConfig()\n\n    with create_transfer_manager(self, config) as manager:\n        future = manager.upload(\n            fileobj=Fileobj,\n            bucket=Bucket,\n            key=Key,\n            extra_args=ExtraArgs,\n            subscribers=subscribers,\n        )\n        return future.result()","sourceCodeStart":642,"sourceCodeEnd":678,"githubUrl":"https://github.com/boto/boto3/blob/6e10b029c1326a437932a8b24f38af69fd986e15/boto3/s3/inject.py#L642-L678","documentation":"Raised by the injected `upload_fileobj` helper before an upload starts. boto3 streams bytes by calling `read()` on the supplied `Fileobj`, so it requires a genuine file-like object. Passing bytes, a string, a path, or any object lacking a `read` method is rejected immediately rather than failing mid-transfer. Use `upload_file` (not `upload_fileobj`) when you only have a filename.","triggerScenarios":"Calling `client.upload_fileobj(Bucket=..., Key=..., Body=<bytes|str|None|dict>)`, `bucket.upload_fileobj(<bytes>, key)`, or `s3.upload_fileobj(fileobj=<object-without-read>)`. Also triggered by an empty/None body variable that was expected to be an open file handle.","commonSituations":"Confusing `upload_file` (takes a path) with `upload_fileobj` (takes an open binary stream); passing `open(path)` in text mode `'r'` (this actually has `read` but corrupts binary data, and some wrappers still fail); forgetting to open the file; passing `b'data'` directly.","solutions":["If you have a path, switch to `client.upload_file(filename, bucket, key)` instead of `upload_fileobj`.","If you have in-memory bytes, wrap them: `from io import BytesIO; client.upload_fileobj(BytesIO(data), bucket, key)`.","If using a real file, open it in binary mode and pass the handle: `with open(path, 'rb') as f: client.upload_fileobj(f, bucket, key)`.","Verify the object is not None before the call: assert the variable holding the body is assigned."],"exampleFix":"# before\nclient.upload_fileobj(b'hello world', 'mybucket', 'key.txt')  # bytes has no .read\n\n# after\nfrom io import BytesIO\nclient.upload_fileobj(BytesIO(b'hello world'), 'mybucket', 'key.txt')","handlingStrategy":"validation","validationCode":"def upload_body(obj):\n    assert hasattr(obj, 'read'), 'upload_fileobj needs a file-like object with read()'\n    return obj\n\nclient.upload_fileobj(upload_body(body), bucket, key)","typeGuard":"from io import IOBase\ndef is_readable_fileobj(o) -> bool:\n    return hasattr(o, 'read') and callable(o.read)","tryCatchPattern":"try:\n    client.upload_fileobj(body, bucket, key)\nexcept ValueError as e:\n    if 'must implement read' in str(e):\n        from io import BytesIO\n        client.upload_fileobj(BytesIO(bytes(body)), bucket, key)  # or upload_file with a path","preventionTips":["Always open files in binary mode ('rb') for uploads.","Use upload_file for paths and upload_fileobj for streams.","Wrap raw bytes in BytesIO before passing to upload_fileobj."],"tags":["s3","upload","fileobj","type-validation"],"backgroundTag":null,"analyzedSha":"6e10b029c1326a437932a8b24f38af69fd986e15","analyzedAt":"2026-08-11T20:52:47.213Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}