Tencent/WeKnora · error

invalid qqbot api_base_url: %w (for private deployments, add

Error message

invalid qqbot api_base_url: %w (for private deployments, add the hostname to SSRF_WHITELIST)

What it means

The QQ bot client validates its HTTP API base URL for SSRF before use. If secutils.ValidateURLForSSRF rejects the host, NewClient fails with this wrapped error explaining how to allow private deployments. This protects against using the bot credentials to reach internal services.

Source

Thrown at internal/im/qqbot/client.go:87

	if result.URL == "" {
		return "", fmt.Errorf("empty qqbot gateway url")
	}
	if err := validateGatewayURL(result.URL); err != nil {
		return "", fmt.Errorf("invalid qqbot gateway url: %w", err)
	}
	return result.URL, nil
}

func validateHTTPAPIBaseURL(raw string) error {
	u, err := url.Parse(raw)
	if err != nil || u.Host == "" {
		return fmt.Errorf("invalid qqbot api_base_url: must be a valid http(s) URL")
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return fmt.Errorf("invalid qqbot api_base_url: must use http or https")
	}
	if err := secutils.ValidateURLForSSRF(raw); err != nil {
		return fmt.Errorf("invalid qqbot api_base_url: %w (for private deployments, add the hostname to SSRF_WHITELIST)", err)
	}
	return nil
}

func validateGatewayURL(raw string) error {
	if strings.TrimSpace(raw) == "" {
		return nil
	}
	u, err := url.Parse(raw)
	if err != nil || u.Host == "" {
		return fmt.Errorf("gateway_url must be a valid wss URL")
	}
	if u.Scheme != "wss" {
		return fmt.Errorf("gateway_url must use wss")
	}
	checkURL := *u
	checkURL.Scheme = "https"
	if err := secutils.ValidateURLForSSRF(checkURL.String()); err != nil {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Add the hostname to the SSRF_WHITELIST environment variable
  2. Use the official QQ bot API base URL (https://api.sgroup.qq.com)
  3. Verify api_base_url parses as a valid http(s) URL with a public host

Example fix

// before
client, err := NewClient(cfg) // api_base_url: http://qqbot-proxy.internal
// after
// export SSRF_WHITELIST=qqbot-proxy.internal
client, err := NewClient(cfg)
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(cfg.APIBaseURL)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
    return fmt.Errorf("invalid qqbot api_base_url: %q", cfg.APIBaseURL)
}

Try / catch

client, err := NewClient(cfg)
if err != nil && strings.Contains(err.Error(), "SSRF_WHITELIST") {
    return fmt.Errorf("qqbot api host blocked: %w", err)
}

Prevention

When it happens

Trigger: NewClient is called with an api_base_url whose hostname is private/loopback/otherwise SSRF-blocked and not in SSRF_WHITELIST.

Common situations: Pointing the client at an internal QQ bot proxy or mock server; localhost in development; SSRF_WHITELIST missing from the container/deployment env.

Related errors


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