siyuan-note/siyuan · error

generated image URL must use HTTPS

Error message

generated image URL must use HTTPS

What it means

downloadGeneratedImage parses the URL returned by the image model and requires scheme https with a non-empty host. This is an SSRF/security guard: plain-http or malformed URLs returned by a compromised or misbehaving provider are rejected before any request is made. Non-https URLs would also leak generated content in cleartext.

Solutions

  1. Configure the provider/proxy to return absolute https:// URLs
  2. If you control the image host, serve it over HTTPS
  3. URL-encode/fix the URL at the provider side; verify with url.Parse what is malformed
  4. As an operator-only workaround behind a trusted private network, host-rewrite the URL to https before passing it downstream (not recommended)

Example fix

// before
rawURL := "http://cdn.example.com/img.png" // rejected: not https
// after
rawURL := "https://cdn.example.com/img.png" // pass
data, err := downloadGeneratedImage(ctx, rawURL)
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(rawURL)
if err != nil || u.Scheme != "https" || u.Host == "" {
    return errors.New("image URL must be absolute https")
}

Prevention

When it happens

Trigger: result.URL from the provider starts with http:// (not https), is scheme-relative like //host/img, or fails url.Parse entirely (spaces, control chars, relative path).

Common situations: Self-hosted/proxied image service returning http:// LAN URLs; provider returning a relative path instead of an absolute URL; corrupted URL containing unencoded characters; man-in-the-middle or malicious provider response.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/89206ce5d22e9f48. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/openai.go:930

	} else if result.URL != "" {
		data, err = downloadGeneratedImage(requestCtx, result.URL)
	} else {
		err = errors.New("image model returned neither base64 data nor URL")
	}
	if err != nil {
		return GeneratedImage{}, err
	}
	mimeType, extension, err := ValidateGeneratedImage(data)
	if err != nil {
		return GeneratedImage{}, err
	}
	return GeneratedImage{Data: data, MIMEType: mimeType, Extension: extension, RevisedPrompt: result.RevisedPrompt}, nil
}

func downloadGeneratedImage(ctx context.Context, rawURL string) ([]byte, error) {
	parsed, err := url.Parse(rawURL)
	if err != nil || parsed.Scheme != "https" || parsed.Host == "" {
		return nil, errors.New("generated image URL must use HTTPS")
	}
	if err = CheckHostSSRF(parsed.Hostname()); err != nil {
		return nil, err
	}
	client := generatedImageHTTPClient()
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)
	if err != nil {
		return nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, fmt.Errorf("download generated image failed with status %d", resp.StatusCode)
	}
	if resp.ContentLength > maxGeneratedImageBytes {

View on GitHub (pinned to 9f775e8a12)