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

  1. Ensure the request has a non-nil URL before dispatch: http.NewRequest always sets it — use it instead of struct literals.
  2. Guard callers that may pass nil requests into the transport.
  3. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/b5ed5ae37e08a700. Report an issue: GitHub.