cloudwego / cloudwego/eino-ext

Claude Bedrock: Config.HTTPClient causes panic with AWS_CA_BUNDLE + is ignored for API calls

Open
#712 1 comment 0 reactions 0 assignees View on GitHub
C-bug D-chatmodel-impl
Dominant language
Go
Stars
811
Forks
368
Avg merge
16h 22m
Merged PRs (30d)
13

Description

**Describe the bug**

Two bugs related to `Config.HTTPClient` in the Bedrock code path:

1. **Panic when `AWS_CA_BUNDLE` is set**: Passing `*http.Client` to `awsConfig.WithHTTPClient` causes a panic because the AWS SDK type-asserts it to `*awshttp.BuildableClient`
2. **HTTPClient ignored for API calls**: Even without the panic, the custom `HTTPClient` is never used for actual Bedrock API requests — it's only passed to the AWS SDK config (for credential resolution), not to the Anthropic SDK's `option.WithHTTPClient`

Both bugs affect users behind corporate proxies (e.g., Teleport `tsh proxy aws`) who need a custom HTTP client to trust a local CA certificate.

---

## Bug 1: Panic when `AWS_CA_BUNDLE` is set

**To Reproduce**

1. Set `AWS_CA_BUNDLE` to any valid PEM file path
2. Create a Bedrock chat model:

```go
chatModel, err := claude.NewChatModel(ctx, &claude.Config{
ByBedrock: true,
Model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
HTTPClient: &http.Client{},
})
```

3. Panic:

```
interface conversion: *http.Client is not *awshttp.BuildableClient
```

**Root cause**

In `claude.go` (Bedrock path):

```go
if config.HTTPClient != nil {
opts = append(opts, awsConfig.WithHTTPClient(config.HTTPClient))
}
```

This passes `*http.Client` to the AWS SDK config loader. When `AWS_CA_BUNDLE` is set, the AWS SDK's `resolveCustomCABundle` in `resolve.go` does:

```go
cfg.HTTPClient = cfg.HTTPClient.(*awshttp.BuildableClient).WithTransportOptions(...)
```

A plain `*http.Client` doesn't satisfy `*awshttp.BuildableClient`, causing the panic.

---

## Bug 2: HTTPClient not used for actual API calls

**Symptom**: Even with a custom `HTTPClient` that trusts a proxy CA, Bedrock requests fail with TLS certificate errors.

**Root cause**

Compare the Bedrock path vs. the direct API path in `claude.go`:

```go
// Bedrock path — HTTPClient only goes to AWS SDK config (credential resolution)
if config.HTTPClient != nil {
opts = append(opts, awsConfig.WithHTTPClient(config.HTTPClient))
}
cli = anthropic.NewClient(bedrock.WithLoadDefaultConfig(ctx, opts...))

// Direct API path — HTTPClient correctly goes to Anthropic SDK options
if config.HTTPClient != nil {
opts = append(opts, option.WithHTTPClient(config.HTTPClient))
}
cli = anthropic.NewClient(opts...)
```

In the Bedrock path, `config.HTTPClient` is passed to `awsConfig.WithHTTPClient()` (used during AWS credential/config loading), but **not** to `option.WithHTTPClient()` (used for actual Anthropic SDK HTTP requests). The Anthropic SDK falls back to `http.DefaultClient` for all Bedrock API calls, ignoring the user's custom transport/TLS configuration.

---

## Suggested fix

```go
} else if config.ByBedrock {
var opts []func(*awsConfig.LoadOptions) error
// ... region, credentials setup ...

if config.HTTPClient != nil {
// Bug 1 fix: wrap in BuildableClient so AWS_CA_BUNDLE resolution works
opts = append(opts, awsConfig.WithHTTPClient(
awshttp.NewBuildableClient().WithTransportOptions(func(t *http.Transport) {
if tr, ok := config.HTTPClient.Transport.(*http.Transport); ok {
*t = *tr
}
}),
))
}

// Bug 2 fix: pass HTTPClient to Anthropic SDK for actual API calls
bedrockOpts := []option.RequestOption{}
if config.HTTPClient != nil {
bedrockOpts = append(bedrockOpts, option.WithHTTPClient(config.HTTPClient))
}
cli = anthropic.NewClient(
append(bedrockOpts, bedrock.WithLoadDefaultConfig(ctx, opts...))...,
)
```

Alternatively for Bug 1, simply use `awshttp.NewBuildableClient()` as the default HTTP client when none is provided, which is what the AWS SDK does internally.

**Environment**

- eino-ext: latest main
- Go: 1.23+
- AWS SDK Go v2
- anthropic-sdk-go

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.