awslabs / awslabs/aws-crt-python

AIO HTTP/2 writer task raises unhandled AWS_ERROR_HTTP_STREAM_HAS_COMPLETED during normal shutdown

Open
#762 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.