siyuan-note/siyuan · error
download custom emoji failed: %w
Error message
download custom emoji failed: %w
What it means
Returned by downloadCustomEmojiData (system.go:336) when the HTTP GET to fetch the custom-emoji URL failed at the transport level (DNS, connection refused, TLS handshake, timeout, etc.). The underlying error is wrapped with %w so the cause is preserved; the response may not have been received at all, so no status code is reported.
Source
Thrown at kernel/api/system.go:336
return io.ReadAll(io.LimitReader(file, maxCustomEmojiSize+1))
}
rawURL := strings.TrimSpace(c.PostForm("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 251596fc0d)
Solutions
- Verify the URL is reachable from the SiYuan host (curl -I <url>) and the TLS cert is valid.
- If the host is blocked by a corporate proxy, configure the kernel HTTP proxy settings and retry.
- Retry once for transient failures; if it persists, download the file and use the 'file' upload mode instead.
- Check the wrapped error (err.Unwrap / errors.Unwrap) for the exact transport cause (DNS, TLS, timeout).
Defensive patterns
Strategy: retry
Validate before calling
// Pre-check reachability is not guaranteed; wrap in retry with backoff
async function downloadWithRetry(url, n=2) {
for (let i=0;i<n;i++){ try { return await downloadEmoji(url); } catch(e){ if (/download custom emoji failed/.test(e.message) && i<n-1) await sleep(500*(i+1)); else throw e; } }
} Try / catch
try { await uploadEmojiFromUrl(url); }
catch (e) {
if (/download custom emoji failed/.test(e.msg)) { /* inspect e.cause: DNS/TLS/timeout; fix and retry, or fall back to file upload */ }
else throw e;
} Prevention
- Verify the URL is reachable from the SiYuan host (curl -I) before submitting.
- Configure the kernel HTTP proxy if the host is behind a corporate proxy.
- Fall back to the 'file' upload mode when the remote host is persistently unreachable.
- Inspect the wrapped cause (errors.Unwrap) to distinguish DNS vs TLS vs timeout.
When it happens
Trigger: The emoji `url` points to a host that does not resolve, refuses the connection, has an expired/broken TLS certificate, or the request exceeded the custom-request-client timeout. util.NewCustomReqClient().R().Get(parsedURL.String()) at system.go:334 returns a non-nil err and it is wrapped at line 336.
Common situations: Offline or behind a firewall/proxy that blocks the emoji host. Stale/expired CDN link. Host requires auth or blocks the SiYuan user-agent. Transient network blip. Self-signed or outdated CA store causing TLS failure.
Related errors
- invalid custom emoji URL
- missing query param [u]
- decode [u] failed: %s
- parse [u] failed: %s
- decode [h] failed: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/1fd3ea8eb9a0ff8d.
Report an issue: GitHub.