siyuan-note/siyuan · error
download custom emoji failed with status %d
Error message
download custom emoji failed with status %d
What it means
Returned by downloadCustomEmojiData when the remote URL passed scheme/host validation but the HTTP GET returned a status other than 200 OK. The %d is filled with response.StatusCode. This is the catch-all for 4xx/5xx from the emoji host (404 missing file, 401/403 auth, 500 server error, etc.).
Source
Thrown at kernel/api/system.go:340
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 {
return nil, "", fmt.Errorf("custom emoji file must not be empty")
}
raster := trueView on GitHub (pinned to 251596fc0d)
Solutions
- Open the URL directly in a browser to read the actual status code and body the host returns.
- If 404/410, switch to a URL that still hosts the image, or upload the file directly via the file form field instead of url.
- If 401/403, host the emoji on a CDN/object-store that permits unauthenticated GET, or pre-download and upload as a file.
- If 5xx, retry after the remote service recovers; do not treat it as a SiYuan bug.
Example fix
// before emojiURL := "https://cdn.example.com/old/icon.png" data, err := downloadCustomEmojiData(emojiURL) // 404 -> status error // after: host the asset on a reachable, unauthenticated URL emojiURL := "https://my-bucket.s3.example.com/emojis/icon.png" // or upload the file directly: // POST /api/system/addCustomEmoji form field: file=@icon.png
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the URL is reachable with a HEAD before submitting to addCustomEmoji
resp, err := http.Head(rawURL)
if err != nil { return fmt.Errorf("emoji URL unreachable: %w", err) }
if resp.StatusCode != http.StatusOK { return fmt.Errorf("emoji host returned %d", resp.StatusCode) }
if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(ct, "image/") {
return fmt.Errorf("emoji URL is not an image: %s", ct)
} Try / catch
data, err := downloadCustomEmojiData(rawURL)
if err != nil {
if strings.Contains(err.Error(), "failed with status") {
// remote-side error; surface the status to the user, do not retry 4xx
return fmt.Errorf("emoji source refused: %s", err)
}
return err
} Prevention
- Host emoji assets on a CDN/object store that permits anonymous GET and returns correct Content-Type.
- Avoid hotlinking from sites with anti-leech protection.
- When in doubt, upload the file directly via the file form field instead of the url field.
When it happens
Trigger: POST /api/system/addCustomEmoji with the url form field (no file upload) where the resolved URL is reachable but returns non-200: a typo'd path on a CDN (404), a hotlink-protected host (403), or a temporarily down server (5xx).
Common situations: Pasting a stale image link whose host deleted the asset; hotlink protection on the source site; the URL points to an HTML login page (200 with HTML would instead fail at content-type detection, but a 302-to-login followed by 401 lands here); corporate proxy returning 502.
Related errors
- read custom emoji response failed: %w
- invalid custom emoji URL
- download custom emoji failed: %w
- custom emoji file is too large
- custom emoji file must not be empty
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/7f9697b0c2a85c42.
Report an issue: GitHub.