Tencent/WeKnora · error · ErrUnsafeOutboundURL
ErrUnsafeOutboundURL
ErrUnsafeOutboundURL
Error message
%w: empty URL
What it means
OutboundURLPolicy.Validate is the first-line guard for agent-initiated outbound HTTP. An empty (or whitespace-only) URL cannot be checked, so it is rejected immediately with ErrUnsafeOutboundURL to fail closed rather than allowing an unvalidated request.
Source
Thrown at internal/sandbox/url_guard.go:80
func SafeDialControl(network string, address string, conn syscall.RawConn) error {
return DefaultOutboundURLPolicy().DialControl(network, address, conn)
}
func SafeDialControlForPolicy(policy OutboundURLPolicy) func(string, string, syscall.RawConn) error {
return func(network string, address string, conn syscall.RawConn) error {
return policy.DialControl(network, address, conn)
}
}
// Validate reports whether raw is an acceptable tenant-supplied endpoint. It
// rejects non-HTTP schemes and any host that resolves to a forbidden address.
//
// Callers must ALSO install DialControl on the dialer they use; Validate alone
// cannot close the DNS-rebinding window.
func (p OutboundURLPolicy) Validate(raw string) error {
raw = strings.TrimSpace(raw)
if raw == "" {
return fmt.Errorf("%w: empty URL", ErrUnsafeOutboundURL)
}
parsed, err := url.Parse(raw)
if err != nil {
return fmt.Errorf("%w: %v", ErrUnsafeOutboundURL, err)
}
switch strings.ToLower(parsed.Scheme) {
case "http", "https":
default:
return fmt.Errorf("%w: scheme %q is not allowed", ErrUnsafeOutboundURL, parsed.Scheme)
}
host := parsed.Hostname()
if host == "" {
return fmt.Errorf("%w: missing host", ErrUnsafeOutboundURL)
}
// ".local" is mDNS; "localhost" is only acceptable under the opt-in.
lower := strings.ToLower(host)
if strings.HasSuffix(lower, ".local") {View on GitHub (pinned to 988cbb0330)
Solutions
- Supply a non-empty http(s) URL before calling, e.g. from config or flags.
- Check for empty input at startup and fail configuration loading early with a named field in the message.
- If the URL is legitimately optional, skip the call instead of validating an empty string.
Example fix
// before
var endpoint string // never set
err := policy.Validate(endpoint)
// after
endpoint := os.Getenv("WEBHOOK_URL")
if endpoint == "" {
return errors.New("WEBHOOK_URL must be set")
}
err := policy.Validate(endpoint) Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(rawURL) == "" {
return errors.New("outbound URL is required")
} Type guard
func nonEmptyURL(s string) bool { return strings.TrimSpace(s) != "" } Try / catch
err := policy.Validate(raw)
if errors.Is(err, sandbox.ErrUnsafeOutboundURL) {
return fmt.Errorf("outbound URL rejected: %w", err)
} Prevention
- Fail fast at config load when required URL fields are empty.
- Distinguish optional vs required URL fields in your config schema.
- Trim whitespace from env/config values before use.
When it happens
Trigger: Calling Validate or ValidateOutboundURLWithPolicy with "" or a string that is only whitespace after TrimSpace — typically an unset config field or a variable that was never populated.
Common situations: Missing environment variable / config key for a webhook or API base URL; template placeholder not substituted ("{{url}}" would hit scheme check, truly empty hits this); optional URL fields left blank.
Related errors
- %s failed SSRF validation: %w
- join request not found
- failed to retrieve: %s
- opensearch: index not found
- 2201
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/f75828e875676845.
Report an issue: GitHub.