Skip to content

ClientFactory.create() mutates shared ClientConfig.extensions across calls #858

@matanweks

Description

@matanweks

Bug Description

ClientFactory is designed for reuse — create one factory, call create() multiple times for different agents. However, when create() is called with per-client extensions, the merged list is written back to self._config.extensions, permanently mutating the shared config. Extensions silently accumulate across calls.

Reproduction

config = ClientConfig(
    httpx_client=httpx.AsyncClient(),
    extensions=['base-ext'],
)
factory = ClientFactory(config)

factory.create(card, extensions=['ext-a'])
factory.create(card, extensions=['ext-b'])

# BUG: config.extensions is now ['base-ext', 'ext-a', 'ext-b']
# Expected: config.extensions == ['base-ext']

Root Cause

In src/a2a/client/client_factory.py, the create() method:

all_extensions = self._config.extensions.copy()
if extensions:
    all_extensions.extend(extensions)
    self._config.extensions = all_extensions  # <-- mutates shared config

Line 242 writes the merged list back to self._config.extensions.

Expected Behavior

create() should produce a per-call config (using dataclasses.replace) and never mutate the factory's shared ClientConfig.

Related

This is the same class of bug as #744 (mutable field defaults in ServerCallContext).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions