Tencent/WeKnora · error
default HTTP transport is not *http.Transport
Error message
default HTTP transport is not *http.Transport
What it means
NewSearchHTTPClient clones http.DefaultTransport to build an SSRF-safe client, and requires it to be a concrete *http.Transport. If some other package has replaced http.DefaultTransport with a custom RoundTripper (or nil), the type assertion fails and this error is returned at client construction time.
Source
Thrown at internal/infrastructure/web_search/proxy.go:29
)
// ValidateProxyURL delegates to utils.ValidateURLForSSRF (only http/https pass that check).
func ValidateProxyURL(proxyURL string) error {
proxyURL = strings.TrimSpace(proxyURL)
if proxyURL == "" {
return nil
}
return utils.ValidateURLForSSRF(proxyURL)
}
// NewSearchHTTPClient builds an http.Client for outbound web search requests.
// It uses utils.SSRFSafeDialContext, optional explicit or environment proxy, and
// redirect validation consistent with utils.NewSSRFSafeHTTPClient.
func NewSearchHTTPClient(timeout time.Duration, proxyURL string) (*http.Client, error) {
proxyURL = strings.TrimSpace(proxyURL)
def, ok := http.DefaultTransport.(*http.Transport)
if !ok {
return nil, fmt.Errorf("default HTTP transport is not *http.Transport")
}
t := def.Clone()
t.DialContext = utils.SSRFSafeDialContext
if proxyURL != "" {
if err := ValidateProxyURL(proxyURL); err != nil {
return nil, err
}
u, err := url.Parse(proxyURL)
if err != nil {
return nil, fmt.Errorf("invalid proxy_url: %w", err)
}
if u.Scheme == "" || u.Host == "" {
return nil, fmt.Errorf("invalid proxy_url: scheme and host are required")
}
t.Proxy = http.ProxyURL(u)
} else {
t.Proxy = http.ProxyFromEnvironmentView on GitHub (pinned to 988cbb0330)
Solutions
- Stop replacing http.DefaultTransport globally; wrap per-request instead
- If replacement is required, assign a *http.Transport (e.g. def.Clone() with wrapped RoundTrip)
- Initialize the search providers before any code mutates http.DefaultTransport
- Construct providers with their own transport instead of relying on the default
Example fix
// before
http.DefaultTransport = otelhttp.NewTransport(http.DefaultTransport)
// after
customClient := &http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport.(*http.Transport).Clone())} Defensive patterns
Strategy: type-guard
Validate before calling
if _, ok := http.DefaultTransport.(*http.Transport); !ok {
return fmt.Errorf("search client unavailable: default transport was replaced")
} Type guard
func defaultTransportIsCloneable() bool {
_, ok := http.DefaultTransport.(*http.Transport)
return ok
} Try / catch
client, err := web_search.NewSearchHTTPClient(timeout, proxy)
if err != nil {
if strings.Contains(err.Error(), "default HTTP transport is not") {
log.Printf("transport replaced globally; constructing own transport")
return buildClientWithOwnTransport(timeout, proxy)
}
return err
} Prevention
- Never assign http.DefaultTransport globally in app or library init()
- Wrap transports per-client instead of mutating the default
- Run integration tests that construct providers to catch init-order issues
- Audit third-party libs that patch the default transport
When it happens
Trigger: Any of NewBaiduProvider/NewBingProvider/NewDuckDuckGoProvider/NewExaProvider/NewGoogleProvider/NewKeenableProvider constructed after app code assigned a non-*http.Transport RoundTripper to http.DefaultTransport (e.g. http.DefaultTransport = myInstrumentedTripper).
Common situations: Instrumentation/OTel or mocking libraries replacing the default transport in init(), a test helper leaked into production code, or a dependency mutating the global transport.
Related errors
- failed to initialize TOS client: %w
- create request: %w
- create request: %w
- create request: %w
- failed to create request: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/333feb41adadca5d.
Report an issue: GitHub.