siyuan-note/siyuan · error

download custom emoji failed

Error message

download custom emoji failed: %w

What it means

After URL validation, downloadCustomEmojiData performs an HTTP GET with util.NewCustomReqClient(). If the request itself fails (DNS failure, connection refused, TLS error, timeout) the error is wrapped as "download custom emoji failed: %w". This is a transport-level failure, not a non-200 status (that yields a separate message).

Solutions

  1. Open the emoji URL in a browser to confirm it is reachable from your machine
  2. Check DNS/proxy/firewall settings; configure proxy environment variables if the kernel is behind one
  3. Use a URL on a reachable, trusted HTTPS host (e.g. re-upload the image elsewhere)
  4. Retry if the failure was transient (timeout, connection reset)

Example fix

// before
addEmoji({ url: "https://internal-lan/emoji.png" }) // kernel cannot reach internal host
// after
addEmoji({ url: "https://cdn.example.com/emoji.png" }) // publicly reachable host
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await addEmoji({ url });
} catch (e) {
  if (String(e).includes("download custom emoji failed")) {
    console.error("Network error fetching emoji; check host reachability/proxy", e);
  }
}

Prevention

When it happens

Trigger: Target host unreachable or DNS-unresolvable, server rejects the connection, TLS certificate errors, network offline, or request timeout during emoji download.

Common situations: Emoji hosted on an intranet host not reachable from the kernel; firewall/proxy blocking the request; expired or self-signed certificates; the image host rate-limiting or dropping connections; corporate proxy not configured for the kernel process.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at kernel/api/system.go:344

		return io.ReadAll(io.LimitReader(file, maxCustomEmojiSize+1))
	}

	rawURL := strings.TrimSpace(request.URL)
	if rawURL == "" {
		return nil, fmt.Errorf("field [file] or [url] must not be empty")
	}
	return downloadCustomEmojiData(rawURL)
}

func downloadCustomEmojiData(rawURL string) ([]byte, error) {
	parsedURL, err := url.Parse(rawURL)
	if err != nil || (parsedURL.Scheme != "http" && parsedURL.Scheme != "https") || parsedURL.Host == "" {
		return nil, fmt.Errorf("invalid custom emoji URL")
	}

	response, err := util.NewCustomReqClient().R().Get(parsedURL.String())
	if err != nil {
		return nil, fmt.Errorf("download custom emoji failed: %w", err)
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("download custom emoji failed with status %d", response.StatusCode)
	}
	if response.ContentLength > maxCustomEmojiSize {
		return nil, fmt.Errorf("custom emoji file is too large")
	}

	data, err := io.ReadAll(io.LimitReader(response.Body, maxCustomEmojiSize+1))
	if err != nil {
		return nil, fmt.Errorf("read custom emoji response failed: %w", err)
	}
	return data, nil
}

func normalizeCustomEmojiData(data []byte) (normalized []byte, ext string, err error) {
	if len(data) == 0 {

View on GitHub (pinned to 9f775e8a12)