boto/boto3 · error · ValueError
Fileobj must implement write
Error message
Fileobj must implement write
What it means
Raised by the injected `download_fileobj` helper before a download starts. boto3 writes incoming bytes by calling `write()` on the supplied `Fileobj`, so the target must be a writable binary stream. Passing bytes, a string, a path, or a read-only object is rejected up front. Use `download_file` when you want to write directly to a path.
Solutions
- If you want a file on disk by path, use `client.download_file(bucket, key, filename)` instead of `download_fileobj`.
- Pass an open writable binary handle: `with open(path, 'wb') as f: client.download_fileobj(bucket, key, f)`.
- For in-memory capture, use `from io import BytesIO; buf = BytesIO(); client.download_fileobj(bucket, key, buf)`.
- Ensure the destination handle is opened in write/append binary mode (`'wb'`/`'ab'`), not read mode.
Example fix
# before
client.download_fileobj('mybucket', 'key.txt', '/tmp/key.txt') # path string has no .write
# after
with open('/tmp/key.txt', 'wb') as f:
client.download_fileobj('mybucket', 'key.txt', f) Defensive patterns
Strategy: validation
Validate before calling
def download_target(obj):
assert hasattr(obj, 'write'), 'download_fileobj needs a writable file-like object'
return obj
with open(path, 'wb') as f:
client.download_fileobj(bucket, key, download_target(f)) Type guard
def is_writable_fileobj(o) -> bool:
return hasattr(o, 'write') and callable(o.write) Try / catch
try:
client.download_fileobj(bucket, key, target)
except ValueError as e:
if 'must implement write' in str(e):
with open(target, 'wb') as f:
client.download_fileobj(bucket, key, f) # target was a path Prevention
- Open destination files in write-binary ('wb').
- Use download_file for paths and download_fileobj for open streams.
- Never pass a path string or None as the Fileobj argument.
When it happens
Trigger: Calling `client.download_fileobj(Bucket=..., Key=..., Fileobj=<bytes|str|path|None>)` or `bucket.download_fileobj(key, <read-only-or-non-file-object>)`. Common when a variable intended to be an open file is actually a path string or None.
Common situations: Confusing `download_file` (takes a path) with `download_fileobj` (takes an open writable stream); passing a path string; passing a BytesIO opened/used incorrectly; forgetting to open the destination; passing a file opened in `'rb'` (read-only) mode.
Related errors
- Fileobj must implement read
- Filename must be a string or a path-like object
- Max Retries Exceeded
- CRT transfer client is configured but is missing minimum…
- Either a boto3.Client or s3transfer.manager.TransferManager…
AI-assisted analysis of boto/boto3@6e10b029c1 (2026-08-11).
Data as JSON: /api/errors/cb87edc34bdcb3a1.
Report an issue: GitHub.
Appendix: 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 6e10b029c1)