siyuan-note/siyuan · warning

URL has no host

Error message

URL has no host

What it means

WebFetch parses the raw URL with net/url.Parse and requires an http(s) scheme; this error is returned when the parsed URL has an empty Host component (e.g. 'https://' or 'file:///tmp/x' style inputs that still pass the scheme check). It is a fail-fast input validation guard before any network activity or SSRF checks run.

Solutions

  1. Check the URL includes a host part before calling WebFetch: u, _ := url.Parse(raw); require u.Host != ""
  2. Ensure the scheme is included ('https://example.com', not 'example.com' or '//example.com')
  3. Trim whitespace and hidden characters from the input URL; log the exact string passed in
  4. If the URL comes from user content, normalize/repair it (prepend https:// when scheme is missing) before calling

Example fix

// before
WebFetch("example.com/page", "markdown") // rejected: no scheme/host

// after
WebFetch("https://example.com/page", "markdown")
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(raw)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
    return errors.New("skipping: URL must be an absolute http(s) URL with a host")
}

Type guard

func isFetchableURL(raw string) bool {
    u, err := url.Parse(strings.TrimSpace(raw))
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Prevention

When it happens

Trigger: Calling WebFetch with 'https://', 'http://', a scheme-relative URL like '//example.com/x' (no scheme so rejected earlier — but 'https:' alone parses with empty Host), or a malformed URL whose host part is dropped by url.Parse.

Common situations: Building the URL by string concatenation where the host variable is empty; reading a URL from config or a document where the host was stripped; passing a path-only or protocol-relative link from user input.

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 siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/065f52931c69ff16. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/webfetch.go:46

	"strings"

	"github.com/88250/gulu"
	"github.com/88250/lute"
)

const (
	maxWebFetchBytes     = 5 * 1024 * 1024  // text/html, text/plain
	maxWebFetchFileBytes = 10 * 1024 * 1024 // file/image download
	maxWebFetchChars     = 50000
)

func WebFetch(rawURL, format string) (string, error) {
	u, err := url.Parse(rawURL)
	if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
		return "", errors.New("URL must start with http:// or https://")
	}
	if u.Host == "" {
		return "", errors.New("URL has no host")
	}

	if err := CheckHostSSRF(u.Hostname()); err != nil {
		return "", err
	}

	resp, err := ssrfSafeClient.Get(rawURL)
	if err != nil {
		return "", errors.New("fetch failed: " + err.Error())
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		return "", fmt.Errorf("HTTP %d", resp.StatusCode)
	}

	contentType := resp.Header.Get("Content-Type")
	maxReadBytes := int64(maxWebFetchBytes)

View on GitHub (pinned to 9f775e8a12)