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
- Check the URL includes a host part before calling WebFetch: u, _ := url.Parse(raw); require u.Host != ""
- Ensure the scheme is included ('https://example.com', not 'example.com' or '//example.com')
- Trim whitespace and hidden characters from the input URL; log the exact string passed in
- 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
- Always store and pass absolute URLs including the scheme
- Normalize user-supplied links (trim spaces, prepend https:// when scheme missing) before fetching
- Add a pre-call url.Parse check in any wrapper around WebFetch
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
- CalDAV: calendar object path is invalid
- CalDAV: calendar path is invalid
- CardDAV: address book path is invalid
- CardDAV: path is invalid
- Conf.Language(142)
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)