ConverseStream fails from AWS SDK for JavaScript v3: TLS ALPN 'no application protocol' (no h2)

Open
#31 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
47/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
aws, javascript, rust

Research direction

Start by tracing the emulator's HTTPS listener and TLS ALPN negotiation; the issue does not name source files or tests. Check how the listener handles HTTP/2 and Bedrock Runtime streaming requests, then reproduce with the JavaScript SDK's default ConverseStream client. Done means that client negotiates h2 and receives the stream while the HTTP/1.1 workaround and existing HTTPS behavior continue to work.

Written by the indexing model from the issue text.

Description

Before you file
  • I searched open and recently closed issues and found no report of this.
  • I checked that this still happens with the latest version of the emulator.
What happened

ConverseStream from the AWS SDK for JavaScript v3 (@aws-sdk/client-bedrock-runtime) fails against the emulator with a TLS ALPN error. The SDK's default client for Bedrock event-stream operations negotiates HTTP/2 only (it offers only h2 in ALPN). The emulator's HTTPS listener negotiates only http/1.1, so the TLS handshake is rejected with alert 120 (no application protocol). Real Bedrock endpoints support HTTP/2, so this works against AWS but not against the emulator.

Non-streaming Converse works. ConverseStream also works if the client is given an HTTP/1.1 request handler (NodeHttpHandler).

default client (HTTP/2): FAILED: The pending stream has been canceled (caused by: C0626DFB01000000:error:0A000460:SSL routines:ssl3_read_bytes:tlsv1 alert no application protocol:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:918:SSL alert number 120
) (caused by: C0626DFB01000000:error:0A000460:SSL routines:ssl3_read_bytes:tlsv1 alert no application protocol:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:918:SSL alert number 120
)
NodeHttpHandler (HTTP/1.1): OK (5 events)
What you expected

The default client works, as it does against real Bedrock: the emulator's HTTPS listener should advertise h2 (in addition to http/1.1) via ALPN and serve HTTP/2, at least for Bedrock Runtime streaming operations.

Steps to reproduce

Environment:

  • Run in Podman 5.8.3 on macOS 15.7 (arm64), using an image built from the Dockerfile in the docs
  • Node v26.13.1
  • @aws-sdk/client-bedrock-runtime 3.1167.0
  • @smithy/node-http-handler 4.14.2
  • Client configured through AWS_ENDPOINT_URL=https://127.0.0.1:<port>, AWS_CA_BUNDLE and NODE_EXTRA_CA_CERTS pointing at the emulator's CA (~/.aws/emulator/<port>/ca.pem), dummy credentials, us-east-1
  1. Start the emulator and point the shell at it (endpoint, CA bundle, credentials, region as above).
  2. npm i @aws-sdk/client-bedrock-runtime @smithy/node-http-handler
  3. Save as repro.mjs and run MODEL_ID=anthropic.claude-3-5-sonnet-20241022-v2:0 node repro.mjs
import { BedrockRuntimeClient, ConverseStreamCommand } from "@aws-sdk/client-bedrock-runtime";
import { NodeHttpHandler } from "@smithy/node-http-handler";

const modelId = process.env.MODEL_ID;
const input = { modelId, messages: [{ role: "user", content: [{ text: "hi" }] }] };

async function run(label, client) {
  try {
    const res = await client.send(new ConverseStreamCommand(input));
    let n = 0;
    for await (const _ of res.stream) n++;
    console.log(`${label}: OK (${n} events)`);
  } catch (e) {
    console.log(`${label}: FAILED: ${e.message} (caused by: ${e.cause?.message ?? e.cause})`);
  }
}

await run("default client (HTTP/2)", new BedrockRuntimeClient({}));
await run("NodeHttpHandler (HTTP/1.1)", new BedrockRuntimeClient({ requestHandler: new NodeHttpHandler() }));
Emulator version

aws-emulator 1.0.322 (release 2026.11.10, commit 7753983c6e495ec3612695b1336bf4936fc7b7fd)

Impact and workaround

Pass an HTTP/1.1 handler to the client:

new BedrockRuntimeClient({ requestHandler: new NodeHttpHandler() })

This requires code changes to the application under test, which is what the emulator is meant to avoid.

Additional context

ALPN observations:

Against the emulator's HTTPS port, with the emulator CA:

$ openssl s_client -alpn h2 -connect 127.0.0.1:<port> -CAfile ca.pem
...error:0A000460:SSL routines:ssl3_read_bytes:tlsv1 alert no application protocol ... SSL alert number 120
No ALPN negotiated

$ openssl s_client -alpn http/1.1 -connect 127.0.0.1:<port> -CAfile ca.pem
ALPN protocol: http/1.1

$ curl --http2 -sv --cacert ca.pem https://127.0.0.1:<port>/
* ALPN: curl offers h2,http/1.1
* ALPN: server accepted http/1.1
* using HTTP/1.x

So the listener only negotiates http/1.1, and a client that offers only h2 is rejected at the handshake. I also confirmed with a local TLS server that logs the ClientHello ALPN list that the SDK's default ConverseStream client offers exactly [ 'h2' ].

Dominant language
Rust
Stars
2.2k
Forks
44
PR merge metrics
No merged PRs in 30d

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from aws/aws-emulator

All issues in aws/aws-emulator

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.