Bug
defaultHTTPClient() in default_http_client.go does an unsafe type assertion on http.DefaultTransport:
func defaultHTTPClient() *http.Client {
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.ResponseHeaderTimeout = defaultResponseHeaderTimeout
return &http.Client{Transport: transport}
}
http.DefaultTransport is declared as http.RoundTripper, not *http.Transport. It is common (and recommended by the OpenTelemetry community) to wrap it for distributed tracing:
http.DefaultTransport = otelhttp.NewTransport(http.DefaultTransport)
When any application that does this calls anthropic.NewClient(...), the SDK panics:
panic: interface conversion: http.RoundTripper is *otelhttp.Transport, not *http.Transport
github.com/anthropics/anthropic-sdk-go@v1.41.0/default_http_client.go:21
Why option.WithHTTPClient doesn't help
NewClient always invokes DefaultClientOptions() (which calls defaultHTTPClient()) before appending caller options. So the panic happens during client construction, even when the caller fully replaces the HTTP client via option.WithHTTPClient(...). The default client built by defaultHTTPClient() is then immediately discarded — meaning the SDK is panicking while constructing a client it never uses.
Affected versions
Introduced in v1.39.0 (commit 507cbe5d, 2026-04-24, "feat(go): add default http client with timeout"). Still present on main and in v1.41.0 (latest as of 2026-05-07). v1.38.0 and earlier are unaffected.
Reproduction
package main
import (
"net/http"
"github.com/anthropics/anthropic-sdk-go"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
func main() {
http.DefaultTransport = otelhttp.NewTransport(http.DefaultTransport)
_ = anthropic.NewClient() // panics
}
Suggested fix
Replace the unchecked assertion with a safe one and fall back to a fresh *http.Transport (or to wrapping the existing RoundTripper) when the caller has installed a custom transport:
func defaultHTTPClient() *http.Client {
var transport *http.Transport
if t, ok := http.DefaultTransport.(*http.Transport); ok {
transport = t.Clone()
} else {
// http.DefaultTransport has been wrapped (e.g. by otelhttp).
// Fall back to a fresh *http.Transport so we can still set
// ResponseHeaderTimeout without panicking.
transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
}
transport.ResponseHeaderTimeout = defaultResponseHeaderTimeout
return &http.Client{Transport: transport}
}
(Note: this file is generated by Stainless, so the fix likely needs to be applied at the generator level rather than directly in the repo.)
Workarounds for affected users
The only workarounds today require not wrapping http.DefaultTransport globally and instead wrapping each http.Client.Transport individually — which defeats the simplicity of the global-otel-instrumentation pattern. There is no SDK-level option to skip defaultHTTPClient(): WithoutEnvironmentDefaults skips credential autoload but is documented for a different purpose, and using it to dodge the panic also disables env-based credential resolution as a side effect.
Bug
defaultHTTPClient()indefault_http_client.godoes an unsafe type assertion onhttp.DefaultTransport:http.DefaultTransportis declared ashttp.RoundTripper, not*http.Transport. It is common (and recommended by the OpenTelemetry community) to wrap it for distributed tracing:When any application that does this calls
anthropic.NewClient(...), the SDK panics:Why
option.WithHTTPClientdoesn't helpNewClientalways invokesDefaultClientOptions()(which callsdefaultHTTPClient()) before appending caller options. So the panic happens during client construction, even when the caller fully replaces the HTTP client viaoption.WithHTTPClient(...). The default client built bydefaultHTTPClient()is then immediately discarded — meaning the SDK is panicking while constructing a client it never uses.Affected versions
Introduced in v1.39.0 (commit
507cbe5d, 2026-04-24, "feat(go): add default http client with timeout"). Still present onmainand in v1.41.0 (latest as of 2026-05-07). v1.38.0 and earlier are unaffected.Reproduction
Suggested fix
Replace the unchecked assertion with a safe one and fall back to a fresh
*http.Transport(or to wrapping the existingRoundTripper) when the caller has installed a custom transport:(Note: this file is generated by Stainless, so the fix likely needs to be applied at the generator level rather than directly in the repo.)
Workarounds for affected users
The only workarounds today require not wrapping
http.DefaultTransportglobally and instead wrapping eachhttp.Client.Transportindividually — which defeats the simplicity of the global-otel-instrumentation pattern. There is no SDK-level option to skipdefaultHTTPClient():WithoutEnvironmentDefaultsskips credential autoload but is documented for a different purpose, and using it to dodge the panic also disables env-based credential resolution as a side effect.