Tencent/WeKnora · error

invalid URL: %w

Error message

invalid URL: %w

What it means

This error is returned by the RSS client's fetch when the raw URL string cannot be parsed by net/url.Parse. Note that url.Parse is very lenient; this only fires for genuinely malformed URL syntax (e.g. control characters, invalid percent-escapes like %zz, or a bare colon in the first path segment). By the time this line runs, SSRF validation has already passed, so this is the last URL-syntax gate before the HTTP request is built.

Source

Thrown at internal/datasource/connector/rss/client.go:53

func newClient(headers map[string]string) *client {
	cfg := utils.DefaultSSRFSafeHTTPClientConfig()
	cfg.Timeout = requestTimeout
	return &client{
		httpClient: utils.NewSSRFSafeHTTPClient(cfg),
		headers:    headers,
	}
}

// fetch retrieves rawURL with SSRF validation and size limiting. Custom auth
// headers are only attached when withAuthHeaders is true (feed fetches); article
// pages on third-party domains must not receive feed credentials.
func (c *client) fetch(ctx context.Context, rawURL string, maxSize int64, withAuthHeaders bool) ([]byte, error) {
	if err := utils.ValidateURLForSSRF(rawURL); err != nil {
		return nil, fmt.Errorf("URL rejected: %w", err)
	}
	if _, err := url.Parse(rawURL); err != nil {
		return nil, fmt.Errorf("invalid URL: %w", err)
	}

	ctx, cancel := context.WithTimeout(ctx, requestTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)
	if err != nil {
		return nil, err
	}

	if withAuthHeaders {
		for k, v := range c.headers {
			req.Header.Set(k, v)
		}
	}
	if req.Header.Get("User-Agent") == "" {
		req.Header.Set("User-Agent", defaultUserAgent)
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Print the URL with %q and check for control characters, whitespace, or invalid %-escapes; trim and re-enter the feed URL in the datasource config.
  2. Percent-encode the offending characters (e.g. use url.PathEscape on path components, or strings.TrimSpace on pasted values) before saving the config.
  3. If the URL comes from user input, validate at ingestion time with url.ParseRequestURI and reject/mend it there instead of failing at fetch time.

Example fix

// before
data, err := cli.fetchFeed(ctx, feedURL)
// after
trimmed := strings.TrimSpace(feedURL)
if _, perr := url.Parse(trimmed); perr != nil {
    return fmt.Errorf("configured feed URL is malformed: %w", perr)
}
data, err := cli.fetchFeed(ctx, trimmed)
Defensive patterns

Strategy: validation

Validate before calling

func validFeedURL(raw string) error {
    trimmed := strings.TrimSpace(raw)
    if trimmed == "" {
        return errors.New("empty feed URL")
    }
    u, err := url.Parse(trimmed)
    if err != nil {
        return fmt.Errorf("malformed URL: %w", err)
    }
    if u.Scheme != "http" && u.Scheme != "https" {
        return fmt.Errorf("unsupported scheme %q", u.Scheme)
    }
    return nil
}

Prevention

When it happens

Trigger: A feed URL or article URL stored in the datasource config contains characters that net/url rejects: invalid percent-encoding sequences (e.g. "https://example.com/feed%zz"), ASCII control characters or unescaped spaces/newlines pasted into the URL field, or a first path segment containing a colon (e.g. "https://example.com/foo:bar").

Common situations: Admins paste feed URLs from emails/docs with trailing whitespace or smart quotes; URLs built by string concatenation with unescaped user input; migrations import feed lists from CSV where a comma or newline slipped into the URL cell.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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