boto/boto3 · error · ValueError

Manager cannot be provided with client, config, nor osutil.

Error message

Manager cannot be provided with client, config, nor osutil. These parameters are mutually exclusive.

What it means

Raised by S3Transfer.__init__ when a caller supplies manager= together with any of client=, config=, or osutil=. When you hand in a fully-built TransferManager it already encapsulates its own client/config/osutil, so providing those separately would be ambiguous and ignored; boto3 treats them as mutually exclusive and rejects the combination with this ValueError.

Source

Thrown at boto3/s3/transfer.py:417

                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(
        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.

View on GitHub (pinned to c7b4afac23)

Solutions

  1. Choose one construction style: either pass only manager= (a complete TransferManager), or pass client= (+ optional config=/osutil=) and let S3Transfer build the manager.
  2. If you built the manager from a specific client/config, do not also pass those to S3Transfer; the manager already carries them.
  3. Switch to the injected s3.upload_file/download_file helpers to avoid managing S3Transfer construction entirely.

Example fix

// before
mgr = TransferManager(client, config, osutil)
transfer = S3Transfer(client=client, config=config, manager=mgr)  # mutually exclusive

// after
mgr = TransferManager(client, config, osutil)
transfer = S3Transfer(manager=mgr)
Defensive patterns

Strategy: validation

Validate before calling

if manager is not None and (client is not None or config is not None or osutil is not None):
    raise ValueError('manager is mutually exclusive with client/config/osutil')

Type guard

def transfer_args_consistent(client, config, osutil, manager) -> bool:
    return manager is None or (client is None and config is None and osutil is None)

Try / catch

try:
    transfer = boto3.s3.transfer.S3Transfer(client=client, manager=manager)
except ValueError as e:
    if 'mutually exclusive' in str(e):
        transfer = boto3.s3.transfer.S3Transfer(manager=manager)  # drop client/config

Prevention

When it happens

Trigger: Constructing S3Transfer(client=..., manager=...), S3Transfer(config=..., manager=...), S3Transfer(osutil=..., manager=...), or any combination that includes manager plus one of the others.

Common situations: Migrating code that previously passed a client and then adding a pre-built manager without removing the other arguments; copy-pasting examples that mix the two construction styles.

Related errors


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