Skip to content

[BUG] Systemic Issue in AutoRest-Generated Async Methods: Service Parameters are not Popped from kwargs before Pipeline Call #41959

Open
@rbricheno

Description

@rbricheno

Package Name: azure-storage-blob and likely others using the same code generator.
Package Version: 12.25.1 (and likely others)
Operating System: Ubuntu 22.04 (but the issue is OS-agnostic)
Python Version: 3.10

Describe the bug
There is a systemic bug in the generated asynchronous operation methods, likely originating from the AutoRest Python templates.

When an async method like ContainerClient.list_blobs(max_results=...) is called, the service-level parameter (max_results) is correctly used to build the HTTP request URL. However, the parameter is not removed from the **kwargs dictionary that is subsequently passed down through the azure-core pipeline.

This causes the service-level parameter to be passed all the way to the underlying aiohttp transport layer, which does not recognize it, resulting in a TypeError: ClientSession._request() got an unexpected keyword argument 'max_results'.

The core issue is that the generated async wrapper method fails to clean up its kwargs after consuming the named parameters.

To Reproduce
Steps to reproduce the behavior:

  1. Set up a clean, isolated Python environment:
    python3 -m venv venv
    source venv/bin/activate
  2. Create a requirements.txt file with the following content: This specifies the latest stable versions that reliably demonstrate the issue.
    azure-storage-blob==12.25.1
    aiohttp==3.8.6
    
  3. Install the requirements:
    pip install -r requirements.txt
  4. Create a minimal test script (test_bug.py):
    (Note: This script requires a config.json file in the same directory containing a valid STORAGE_CONN_STR and BLOB_CONTAINER_NAME)
    import asyncio
    import json
    from azure.storage.blob.aio import ContainerClient
    
    async def main():
        print("--- Minimal Reproducer ---")
        try:
            with open("config.json") as f: config = json.load(f)
            storage_conn_str = config["STORAGE_CONN_STR"]
            container_name = config["BLOB_CONTAINER_NAME"]
            print(f"✔ Config loaded for container: {container_name}")
        except Exception as e:
            print(f"✖ Failed to load config: {e}")
            return
    
        client = ContainerClient.from_connection_string(
            storage_conn_str, container_name
        )
        async with client:
            try:
                # This call fails due to the bug
                print("Attempting to call client.list_blobs(max_results=1)...")
                async for _ in client.list_blobs(max_results=1): pass
                print("SUCCESS: list_blobs(max_results=1) worked.")
            except TypeError as e:
                import traceback
                print(f"\nFAIL: Bug reproduced.\n")
                traceback.print_exc()
    
    if __name__ == "__main__":
        asyncio.run(main())
  5. Run the script:
    python3 test_bug.py
    The script will fail with the TypeError.

Expected behavior
The script should execute successfully without errors. The max_results parameter should be used to construct the URL query string and then be consumed, not passed down to the transport layer. The expected output is:

--- Minimal Reproducer ---
✔ Config loaded for container: ...
Attempting to call client.list_blobs(max_results=1)...
SUCCESS: list_blobs(max_results=1) worked.

Screenshots
The traceback from the failure is the most relevant "screenshot":

FAIL: Bug reproduced.

Traceback (most recent call last):
  File "/path/to/test_bug.py", line 29, in main
    async for _ in client.list_blobs(max_results=1):
  File "/path/to/venv/lib/python3.10/site-packages/azure/core/async_paging.py", line 142, in __anext__
    return await self.__anext__()
  ...
  File "/path/to/venv/lib/python3.10/site-packages/azure/core/pipeline/transport/_aiohttp.py", line 317, in send
    result = await self.session.request(  # type: ignore
  File "/path/to/venv/lib/python3.10/site-packages/aiohttp/client.py", line 380, in request
    return _RequestContextManager(self._request(method, url, **kwargs))
TypeError: ClientSession._request() got an unexpected keyword argument 'max_results'

Additional context
This issue was diagnosed through a long and detailed process that ruled out environmental factors (venv corruption, caching, network issues, etc.). The final evidence points to a code-generation issue in the AutoRest templates for Python.

Workaround: The bug is not present in all convenience methods. We found that using container_client.walk_blobs(results_per_page=1) works correctly, suggesting it uses a different, non-buggy code path for argument handling.

Suggested Fix: The code-generation template for async operation wrappers should be modified to pop the service-level named parameters from the kwargs dictionary before calling _pipeline.run().

Example diff for the faulty method in azure/storage/blob/_generated/aio/operations/_container_operations.py:

--- a/azure/storage/blob/_generated/aio/operations/_container_operations.py
+++ b/azure/storage/blob/_generated/aio/operations/_container_operations.py
@@ -1651,6 +1651,15 @@
         _request.url = self._client.format_url(_request.url)
 
         _stream = False
+
+        # Pop the service-level parameters from kwargs to prevent them from being passed down
+        # to the transport layer, which would cause a TypeError.
+        kwargs.pop("prefix", None)
+        kwargs.pop("marker", None)
+        kwargs.pop("maxresults", None)
+        kwargs.pop("include", None)
+        kwargs.pop("timeout", None)
+        kwargs.pop("request_id_parameter", None)
+
         pipeline_response: PipelineResponse = await self._client._pipeline.run(  # pylint: disable=protected-access
             _request, stream=_stream, **kwargs
         )

This bug was investigated and diagnosed in partnership with my AI assistant.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ClientThis issue points to a problem in the data-plane of the library.Service AttentionWorkflow: This issue is responsible by Azure service team.StorageStorage Service (Queues, Blobs, Files)customer-reportedIssues that are reported by GitHub users external to the Azure organization.needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK teamquestionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions