boto/boto3 · error · ValueError
Filename must be a string or a path-like object
Error message
Filename must be a string or a path-like object
What it means
Raised by S3Transfer.upload_file after it converts pathlib path-likes to strings and confirms the result is a str. upload_file takes a filesystem path (not a file object) and streams it to S3; if the value is neither a str nor an os.PathLike it cannot be opened, so boto3 rejects it with this ValueError before attempting any transfer.
Source
Thrown at boto3/s3/transfer.py:445
else:
self._manager = create_transfer_manager(client, config, osutil)
def upload_file(
self, filename, bucket, key, callback=None, extra_args=None
):
"""Upload a file to an S3 object.
Variants have also been injected into S3 client, Bucket and Object.
You don't have to use S3Transfer.upload_file() directly.
.. seealso::
:py:meth:`S3.Client.upload_file`
:py:meth:`S3.Client.upload_fileobj`
"""
if isinstance(filename, PathLike):
filename = fspath(filename)
if not isinstance(filename, str):
raise ValueError('Filename must be a string or a path-like object')
subscribers = self._get_subscribers(callback)
future = self._manager.upload(
filename, bucket, key, extra_args, subscribers
)
try:
future.result()
# If a client error was raised, add the backwards compatibility layer
# that raises a S3UploadFailedError. These specific errors were only
# ever thrown for upload_parts but now can be thrown for any related
# client error.
except ClientError as e:
raise S3UploadFailedError(
f"Failed to upload {filename} to {bucket}/{key}: {e}"
)
def download_file(
self, bucket, key, filename, extra_args=None, callback=NoneView on GitHub (pinned to c7b4afac23)
Solutions
- Pass the filesystem path as a string or pathlib.Path: s3.upload_file('/tmp/data.bin', bucket, key).
- If you have an open file handle, switch to s3.upload_fileobj(f, bucket, key).
- If the path comes from another call, assert it is set and is a str/Path before calling: isinstance(filename, (str, pathlib.Path)).
Example fix
// before
with open('/tmp/data.bin', 'rb') as f:
s3.upload_file(f, 'bkt', 'key') # wrong: file handle, not path
// after
s3.upload_file('/tmp/data.bin', 'bkt', 'key')
# or, for a file handle:
with open('/tmp/data.bin', 'rb') as f:
s3.upload_fileobj(f, 'bkt', 'key') Defensive patterns
Strategy: type-guard
Validate before calling
import os, pathlib
if not isinstance(filename, (str, os.PathLike)):
raise TypeError('filename must be a str or os.PathLike')
s3.upload_file(filename, bucket, key) Type guard
def is_upload_path(filename) -> bool:
import os
return isinstance(filename, (str, os.PathLike)) Try / catch
try:
s3.upload_file(filename, bucket, key)
except ValueError as e:
if 'string or a path-like' in str(e):
s3.upload_fileobj(filename, bucket, key) # filename was actually a file handle Prevention
- Use upload_file for paths and upload_fileobj for open handles.
- Assert isinstance(filename, (str, pathlib.Path)) before calling.
- Ensure the path variable is assigned (not None) before the call.
When it happens
Trigger: Calling upload_file(filename, ...) where filename is None, an int, an already-open file handle, a bytes object, or any non-str/non-PathLike value. Commonly: passing an open file where upload_fileobj was intended.
Common situations: Mixing up upload_file (path) vs upload_fileobj (file handle); passing None because the path variable was never assigned; passing a Path subclass that does not implement __fspath__.
Related errors
- Fileobj must implement read
- Either a boto3.Client or s3transfer.manager.TransferManager
- Manager cannot be provided with client, config, nor osutil.
- Fileobj must implement write
- Failed to upload {filename} to {bucket}/{key}: {e}
AI-assisted analysis of boto/boto3@c7b4afac23 (2026-08-04).
Data as JSON: /data/errors/d50d8348d26aef2d.json.
Report an issue: GitHub.