boto/boto3 · error · ValueError

Either a boto3.Client or s3transfer.manager.TransferManager…

Error message

Either a boto3.Client or s3transfer.manager.TransferManager must be provided

What it means

Raised by the `S3Transfer` constructor when neither `client` nor `manager` is supplied. `S3Transfer` needs either a low-level `boto3.client('s3')` to build its own internal manager, or a pre-built `s3transfer.manager.TransferManager`. Most users never instantiate `S3Transfer` directly because the convenience methods on `client`, `Bucket`, and `Object` already wire one up.

Solutions

  1. Prefer the injected helpers (`client.upload_file`, `bucket.download_file`) — they construct S3Transfer correctly for you.
  2. If you must build it, pass the client: `S3Transfer(client=s3_client)`.
  3. Ensure the client is created before the transfer: `s3 = boto3.client('s3'); transfer = S3Transfer(client=s3)`.
  4. Add an assert to catch None early: `assert s3_client is not None`.

Example fix

# before
from boto3.s3.transfer import S3Transfer
transfer = S3Transfer()  # ValueError: Either a boto3.Client or ... must be provided

# after
import boto3
transfer = S3Transfer(client=boto3.client('s3'))

# better: use the injected helper directly
boto3.client('s3').upload_file('/tmp/f', 'bucket', 'key')
Defensive patterns

Strategy: validation

Validate before calling

def make_transfer(client=None, manager=None):
    assert client or manager, 'S3Transfer requires client or manager'
    from boto3.s3.transfer import S3Transfer
    return S3Transfer(client=client, manager=manager)

Type guard

def has_client_or_manager(client, manager) -> bool:
    return bool(client) or bool(manager)

Try / catch

try:
    transfer = S3Transfer(client=s3)
except ValueError:
    s3 = boto3.client('s3')
    transfer = S3Transfer(client=s3)

Prevention

When it happens

Trigger: Calling `S3Transfer()` with all-default arguments, or explicitly `S3Transfer(client=None, manager=None)`. Also when a variable intended to hold the client is None due to a failed/unevaluated client creation.

Common situations: Copy-pasting an example that constructs `S3Transfer` but forgetting to pass the client; refactoring code that previously passed `client=` and accidentally dropping it; the client creation failed earlier and the None propagated.

Related errors


AI-assisted analysis of boto/boto3@6e10b029c1 (2026-08-11). Data as JSON: /api/errors/226664c0e24c98d2. Report an issue: GitHub.

Appendix: source

Thrown at boto3/s3/transfer.py:412

        resolved = {}
        for init_arg, val in init_args.items():
            if val is not None:
                resolved[init_arg] = val
            elif TRANSFER_CONFIG_SUPPORTS_CRT:
                resolved[init_arg] = self.UNSET_DEFAULT
            else:
                resolved[init_arg] = self.DEFAULTS[init_arg]
        return resolved


class S3Transfer:
    ALLOWED_DOWNLOAD_ARGS = TransferManager.ALLOWED_DOWNLOAD_ARGS
    ALLOWED_UPLOAD_ARGS = TransferManager.ALLOWED_UPLOAD_ARGS
    ALLOWED_COPY_ARGS = TransferManager.ALLOWED_COPY_ARGS

    def __init__(self, client=None, config=None, osutil=None, manager=None):
        if not client and not manager:
            raise ValueError(
                'Either a boto3.Client or s3transfer.manager.TransferManager '
                'must be provided'
            )
        if manager and any([client, config, osutil]):
            raise ValueError(
                'Manager cannot be provided with client, config, '
                'nor osutil. These parameters are mutually exclusive.'
            )
        if config is None:
            config = TransferConfig()
        if osutil is None:
            osutil = OSUtils()
        if manager:
            self._manager = manager
        else:
            self._manager = create_transfer_manager(client, config, osutil)

    def upload_file(

View on GitHub (pinned to 6e10b029c1)