Tencent/WeKnora · error
outbound request blocked: base transport is required
Error message
outbound request blocked: base transport is required
What it means
SSRFValidatingRoundTripper.RoundTrip refuses to send the request because the wrapper's Base transport field is nil. The round tripper is purely a validation/delegation layer; without an underlying http.RoundTripper there is nowhere to forward the request, so the library fails fast instead of panicking with a nil pointer dereference. It is a construction/initialization bug, not a network or policy problem.
Source
Thrown at internal/utils/security.go:749
return nil
}
}
// SSRFValidatingRoundTripper enforces the URL policy for every outbound
// request, including URLs discovered at runtime by SDKs (for example OAuth
// metadata) that never passed through an application handler. Dial-time checks
// remain necessary to pin DNS answers and cover transports that cannot accept
// this wrapper directly.
type SSRFValidatingRoundTripper struct {
Base http.RoundTripper
}
func (t *SSRFValidatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if req == nil || req.URL == nil {
return nil, fmt.Errorf("outbound request blocked: request URL is required")
}
if t == nil || t.Base == nil {
return nil, fmt.Errorf("outbound request blocked: base transport is required")
}
if err := validateURLForSSRFForOutbound(req.URL.String()); err != nil {
return nil, fmt.Errorf("outbound request blocked by SSRF policy: %w", err)
}
return t.Base.RoundTrip(req)
}
// NewSSRFSafeHTTPClientWithTransport wraps a caller-supplied transport in an
// *http.Client carrying the given timeout and the SSRF-aware redirect policy.
// Pass a transport from NewSSRFSafeTransport (optionally shared across clients)
// to reuse a single connection pool while keeping per-client timeouts.
func NewSSRFSafeHTTPClientWithTransport(
config SSRFSafeHTTPClientConfig, transport http.RoundTripper,
) *http.Client {
if transport == nil {
transport = NewSSRFSafeTransport(config)
}
return &http.Client{View on GitHub (pinned to 988cbb0330)
Solutions
- Set Base to a real transport, e.g. &SSRFValidatingRoundTripper{Base: http.DefaultTransport} (or a custom *http.Transport) before using it.
- Use the library's constructor (e.g. NewSSRFSafeHTTPClientWithTransport / equivalent NewSSRFValidatingRoundTripper) instead of a raw struct literal so Base is always populated.
- Add an init-time check in your setup code: if rt.Base == nil { return errors.New("round tripper not initialized") } to fail at startup rather than at request time.
Example fix
// before
client := &http.Client{Transport: &utils.SSRFValidatingRoundTripper{}}
// after
client := &http.Client{Transport: &utils.SSRFValidatingRoundTripper{Base: http.DefaultTransport}} Defensive patterns
Strategy: validation
Validate before calling
if rt == nil || rt.Base == nil {
return fmt.Errorf("SSRFValidatingRoundTripper not initialized: Base transport is nil")
} Type guard
func isReadySSRFRoundTripper(t *utils.SSRFValidatingRoundTripper) bool {
return t != nil && t.Base != nil
} Prevention
- Always construct the round tripper through its constructor rather than a raw struct literal.
- Assert Base != nil in application startup/health checks before serving traffic.
- Never copy SSRFValidatingRoundTripper by value after wiring it into a client.
When it happens
Trigger: Calling RoundTrip (directly or via http.Transport/Client using this as RoundTripper) on an SSRFValidatingRoundTripper value created as a zero value (&SSRFValidatingRoundTripper{}) or via a constructor path that never set Base. The test TestSSRFValidatingRoundTripperUsesOutboundCache exercises this wrapper and surfaces it when Base is unset.
Common situations: Declaring the round tripper as a struct literal without assigning Base; copying the wrapper by value after construction in a way that drops the field; wiring it into an http.Client before the underlying transport is initialized; refactoring that renamed/removed the field initialization.
Related errors
- MCP service is required
- sandbox: docker client requires a config
- e2b remote client config is required
- unsafe MinIO endpoint: %w
- unsafe OSS endpoint: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/39f5530e77291366.
Report an issue: GitHub.