Tencent/WeKnora · error
outbound request blocked: request URL is required
Error message
outbound request blocked: request URL is required
What it means
SSRFValidatingRoundTripper.RoundTrip returns this error when the incoming *http.Request is nil or has a nil URL — there is nothing to validate or send. It is a defensive precondition check before SSRF validation and transport dispatch.
Source
Thrown at internal/utils/security.go:746
return fmt.Errorf("%w: %w", ErrSSRFRedirectBlocked, err)
}
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 {View on GitHub (pinned to 988cbb0330)
Solutions
- Ensure the request has a non-nil URL before dispatch: http.NewRequest always sets it — use it instead of struct literals.
- Guard callers that may pass nil requests into the transport.
- If building requests manually, set req.URL = parsedURL before calling RoundTrip.
Example fix
// before
req := &http.Request{Header: http.Header{}}
resp, err := rt.RoundTrip(req) // URL is nil
// after
req, _ := http.NewRequest(http.MethodGet, "https://example.com", nil)
resp, err := rt.RoundTrip(req) Defensive patterns
Strategy: type-guard
Validate before calling
if req == nil || req.URL == nil { return errors.New("request and request.URL are required") } Type guard
func isSendable(req *http.Request) bool { return req != nil && req.URL != nil } Try / catch
if err != nil && strings.Contains(err.Error(), "request URL is required") {
return fmt.Errorf("malformed request reached transport: %w", err)
} Prevention
- Always construct requests with http.NewRequest, not struct literals.
- Nil-check requests in custom middleware before transport dispatch.
- Add a unit test that RoundTrip rejects nil/URL-less requests.
When it happens
Trigger: Calling RoundTrip directly (as in TestSSRFValidatingRoundTripperUsesOutboundCache) with a nil request or a request constructed without a URL, e.g. &http.Request{} with no URL field set.
Common situations: Hand-rolling requests in tests or custom transports, requests deserialized incorrectly, or middleware that drops the URL before the round tripper runs.
Related errors
- %s failed SSRF validation: %w
- service unreachable: %w
- fetch feed %s: %w
- docreader address failed SSRF validation: %w
- create request: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/b5ed5ae37e08a700.
Report an issue: GitHub.