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 S3Transfer.__init__ when neither a client nor a manager argument is supplied. The S3Transfer facade delegates all transfers to an underlying s3transfer TransferManager, which it either receives directly (manager=) or builds from a boto3 client (client=). With neither provided it has nothing to drive transfers with, so it raises this ValueError immediately.

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 c7b4afac23)

Solutions

  1. Pass an S3 client: transfer = boto3.s3.transfer.S3Transfer(boto3.client('s3')).
  2. Prefer the injected high-level API (s3.upload_file / s3.download_file) which constructs the transfer machinery for you and rarely requires S3Transfer directly.
  3. If supplying a custom TransferManager, pass it as manager= (and leave client/config/osutil unset).

Example fix

// before
transfer = boto3.s3.transfer.S3Transfer()  # no client/manager

// after
client = boto3.client('s3')
transfer = boto3.s3.transfer.S3Transfer(client)
Defensive patterns

Strategy: validation

Validate before calling

if client is None and manager is None:
    raise ValueError('Pass either a client or a manager to S3Transfer')
transfer = boto3.s3.transfer.S3Transfer(client=client, manager=manager)

Type guard

def has_transfer_basis(client, manager) -> bool:
    return client is not None or manager is not None

Try / catch

try:
    transfer = boto3.s3.transfer.S3Transfer(client)
except ValueError as e:
    if 'must be provided' in str(e):
        transfer = boto3.s3.transfer.S3Transfer(boto3.client('s3'))

Prevention

When it happens

Trigger: Instantiating S3Transfer() with no arguments: boto3.s3.transfer.S3Transfer(). Also reachable by explicitly passing client=None, manager=None.

Common situations: Directly constructing the lower-level S3Transfer class instead of using the injected s3.upload_file/download_file helpers; refactor that dropped the client argument; passing the client into the wrong parameter name.

Related errors


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