{"record":{"id":"333feb41adadca5d","repo":"Tencent/WeKnora","slug":"default-http-transport-is-not-http-transport","errorCode":null,"errorMessage":"default HTTP transport is not *http.Transport","messagePattern":"default HTTP transport is not \\*http\\.Transport","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/proxy.go","lineNumber":29,"sourceCode":")\n\n// ValidateProxyURL delegates to utils.ValidateURLForSSRF (only http/https pass that check).\nfunc ValidateProxyURL(proxyURL string) error {\n\tproxyURL = strings.TrimSpace(proxyURL)\n\tif proxyURL == \"\" {\n\t\treturn nil\n\t}\n\treturn utils.ValidateURLForSSRF(proxyURL)\n}\n\n// NewSearchHTTPClient builds an http.Client for outbound web search requests.\n// It uses utils.SSRFSafeDialContext, optional explicit or environment proxy, and\n// redirect validation consistent with utils.NewSSRFSafeHTTPClient.\nfunc NewSearchHTTPClient(timeout time.Duration, proxyURL string) (*http.Client, error) {\n\tproxyURL = strings.TrimSpace(proxyURL)\n\tdef, ok := http.DefaultTransport.(*http.Transport)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"default HTTP transport is not *http.Transport\")\n\t}\n\tt := def.Clone()\n\tt.DialContext = utils.SSRFSafeDialContext\n\n\tif proxyURL != \"\" {\n\t\tif err := ValidateProxyURL(proxyURL); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tu, err := url.Parse(proxyURL)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid proxy_url: %w\", err)\n\t\t}\n\t\tif u.Scheme == \"\" || u.Host == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"invalid proxy_url: scheme and host are required\")\n\t\t}\n\t\tt.Proxy = http.ProxyURL(u)\n\t} else {\n\t\tt.Proxy = http.ProxyFromEnvironment","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/proxy.go#L11-L47","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nhttp.DefaultTransport = otelhttp.NewTransport(http.DefaultTransport)\n// after\ncustomClient := &http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport.(*http.Transport).Clone())}","handlingStrategy":"type-guard","validationCode":"if _, ok := http.DefaultTransport.(*http.Transport); !ok {\n    return fmt.Errorf(\"search client unavailable: default transport was replaced\")\n}","typeGuard":"func defaultTransportIsCloneable() bool {\n    _, ok := http.DefaultTransport.(*http.Transport)\n    return ok\n}","tryCatchPattern":"client, err := web_search.NewSearchHTTPClient(timeout, proxy)\nif err != nil {\n    if strings.Contains(err.Error(), \"default HTTP transport is not\") {\n        log.Printf(\"transport replaced globally; constructing own transport\")\n        return buildClientWithOwnTransport(timeout, proxy)\n    }\n    return err\n}","preventionTips":["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"],"tags":["http","transport","configuration","initialization"],"backgroundTag":"default-transport-overridden","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}