awslabs / awslabs/aws-crt-python
AIO HTTP/2 writer task raises unhandled AWS_ERROR_HTTP_STREAM_HAS_COMPLETED during normal shutdown
- Dominant language
- Python
- Stars
- 100
- Forks
- 58
- Avg merge
- 13h 51m
- Merged PRs (30d)
- 2
Description
## Describe the bug
Closing an HTTP/2 bidirectional request through the client's async context managers can leave `AIOHttp2ClientStream._set_request_body_generator()` with an unobserved exception. Its final end-stream write raises `AWS_ERROR_HTTP_STREAM_HAS_COMPLETED`, producing:
```text
Task exception was never retrieved
```
## Regression Issue
Unchecked — I have not established an earlier working version.
## Expected Behavior
Normal stream/client shutdown should not produce an unhandled asyncio task exception. The request-writer task should be observed, and stream completion during its final end-stream write should be handled as part of shutdown.
## Current Behavior
```text
Task exception was never retrieved
future:
Traceback (most recent call last):
File "awscrt/aio/http.py", line 532, in _set_request_body_generator
await self._write_data(None, True)
File "awscrt/aio/http.py", line 524, in _write_data
_awscrt.http2_client_stream_write_data(...)
RuntimeError: 2080 (AWS_ERROR_HTTP_STREAM_HAS_COMPLETED):
HTTP-stream has completed, action cannot be performed.
```
## Reproduction Steps
Requires AWS credentials and access to Amazon Nova Sonic.
```python
import asyncio
import gc
import json
import os
import uuid
from aws_sdk_bedrock_runtime.client import AsyncBedrockRuntimeClient
from aws_sdk_bedrock_runtime.config import AsyncBedrockRuntimeConfig
from aws_sdk_bedrock_runtime.models import (
BidirectionalInputPayloadPart,
InvokeModelWithBidirectionalStreamInputChunk,
InvokeModelWithBidirectionalStreamOperationInput,
)
from smithy_http.aio.crt import AWSCRTHTTPClient
async def send(stream, event):
payload = json.dumps({"event": event}).encode()
await stream.input_stream.send(
InvokeModelWithBidirectionalStreamInputChunk(
value=BidirectionalInputPayloadPart(bytes_=payload)
)
)
async def main():
config = await AsyncBedrockRuntimeConfig.resolve(
region=os.getenv("AWS_REGION", "us-east-1"),
transport=AWSCRTHTTPClient(),
)
async with AsyncBedrockRuntimeClient(config=config) as client:
stream = await client.invoke_model_with_bidirectional_stream(
InvokeModelWithBidirectionalStreamOperationInput(
model_id="amazon.nova-2-sonic-v1:0"
)
)
async with stream:
prompt = str(uuid.uuid4())
await send(stream, {"sessionStart": {"inferenceConfiguration": {}}})
await send(
stream,
{
"promptStart": {
"promptName": prompt,
"textOutputConfiguration": {"mediaType": "text/plain"},
"audioOutputConfiguration": {
"mediaType": "audio/lpcm",
"sampleRateHertz": 16000,
"sampleSizeBits": 16,
"channelCount": 1,
"voiceId": "matthew",
"encoding": "base64",
"audioType": "SPEECH",
},
}
},
)
await send(stream, {"promptEnd": {"promptName": prompt}})
await send(stream, {"connectionEnd": {}})
gc.collect() # Make reporting of the unobserved task deterministic.
await asyncio.sleep(0.1)
asyncio.run(main())
```
## Possible Solution
`AIOHttpClientStreamUnified` creates the request-writer task with `create_task()` but does not subsequently observe it. The stream should retain and retrieve/await that task during shutdown, handling code 2080 when the stream has already completed.
## Additional Information/Context
- Reproduces without an application framework, using the generated client's supported async context managers.
- `aws-sdk-bedrock-runtime==0.11.0`
- `smithy-http==0.5.0`
- Related to, but distinct from, `aws/aws-sdk-python#13`, which reports an `InvalidStateError` on output-stream close.
## aws-crt-python version used
0.32.2
## Python version used
3.12.13
## Operating System and version
macOS 26.6.2
Contributor guide
Research direction
Start in awscrt/aio/http.py at AIOHttp2ClientStream._set_request_body_generator() and _write_data(), then trace how AIOHttpClientStreamUnified creates the request-writer task. Reproduce the shutdown path with the provided async context-manager example; done means the writer task is observed and normal stream completion with code 2080 produces no unhandled asyncio exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, python
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100