Skip to content

Conversation

@jonathan343
Copy link
Contributor

@jonathan343 jonathan343 commented Oct 23, 2025

Overview

This PR fixes InvalidSignatureException errors caused by inconsistent formatting of list-valued headers during request signing. Previously, headers like were sent as value1,value2 but signed as value1, value2, leading to signature mismatches. The SDK now ensures both the request and signature use identical header formatting.

Note

This is a bit weird since the CRT will handle multi-valued headers by adding them individually on the request. The server seems to be handling this by joining them by the , for signature verification.

Testing

Tested this change using the script below with both the AWSCRTHTTPClient and AIOHTTPClient clients:

import asyncio
import json

from smithy_aws_core.identity import EnvironmentCredentialsResolver
from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient
from aws_sdk_bedrock_runtime.models import InvokeModelWithResponseStreamInput
from aws_sdk_bedrock_runtime.config import Config

from smithy_http.aio.aiohttp import AIOHTTPClient

MODEL_ID = "us.amazon.nova-lite-v1:0"


async def test_async():
    c = BedrockRuntimeClient(
        config=Config(
            endpoint_uri="https://bedrock-runtime.us-east-1.amazonaws.com",
            region="us-east-1",
            aws_credentials_identity_resolver=EnvironmentCredentialsResolver(),
            transport=AIOHTTPClient() # Comment to use the default CRT client
        )
    )
    # Define your system prompt(s).
    system_list = [
        {
            "text": "Act as a creative writing assistant. When the user provides you with a topic, write a short story about that topic."
        }
    ]

    # Define one or more messages using the "user" and "assistant" roles.
    message_list = [{"role": "user", "content": [{"text": "A camping trip"}]}]

    # Configure the inference parameters.
    inf_params = {"maxTokens": 500, "topP": 0.9, "topK": 20, "temperature": 0.7}

    request_body = {
        "schemaVersion": "messages-v1",
        "messages": message_list,
        "system": system_list,
        "inferenceConfig": inf_params,
    }
    response = c.invoke_model_with_response_stream(
        InvokeModelWithResponseStreamInput(
            model_id=MODEL_ID,
            body=json.dumps(request_body).encode("utf-8"),
            content_type="application/json"
        )
    )

    async with await response as stream:
        output = ""
        async for r in stream.output_stream:
            try:
                text = json.loads(r.value.bytes_.decode())["contentBlockDelta"][
                    "delta"
                ]["text"]
                output += text
            except Exception:
                continue
        print(f"Response:\n------------\n{output}")


if __name__ == "__main__":
    asyncio.run(test_async())

Without this PR I was receiving the following error:

smithy_core.exceptions.CallError: Unknown error for operation com.amazonaws.bedrockruntime#InvokeModelWithResponseStream - status: 403 - id: com.amazonaws.bedrockruntime#InvalidSignatureException

With this change I received successful responses.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@jonathan343 jonathan343 requested a review from a team as a code owner October 23, 2025 17:28
@jonathan343
Copy link
Contributor Author

After further investigation, I've learned that it doesn't matter what delimiter is used to send multi-valued list headers. What really matters is that we sign with the , delimiter. I think it makes more sense to be consistent across the ecosystem though.

@jonathan343 jonathan343 requested a review from SamRemis October 27, 2025 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants