siyuan-note/siyuan · error
custom emoji file is too large
Error message
custom emoji file is too large
What it means
Returned when the emoji payload exceeds maxCustomEmojiSize (10 MiB). Two throw sites: (1) downloadCustomEmojiData checks response.ContentLength > 10 MiB for the url path; (2) the addCustomEmoji handler checks len(data) > maxCustomEmojiSize for the uploaded file path. Note the url-path check only fires when the server advertises Content-Length; chunked responses with no length skip it and are instead capped by the LimitReader on line 348.
Source
Thrown at kernel/api/system.go:343
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 := true
switch http.DetectContentType(data) {
case "image/png":
ext = ".png"View on GitHub (pinned to 251596fc0d)
Solutions
- Re-export the image at emoji-appropriate dimensions (e.g. 128x128 or 256x256) before uploading.
- Strip metadata and re-compress: pngquant/oxipng for PNG, cwebp for WebP, gifsicle with --lossy for GIF.
- If the emoji must be large, split it or accept the built-in 10 MiB cap cannot be raised without editing maxCustomEmojiSize and rebuilding.
- For the url path, confirm the host sets Content-Length so the size guard actually fires; otherwise the LimitReader silently truncates at 10 MiB+1 and yields a corrupt-image error downstream.
Example fix
// before // user uploads a 24 MiB photo as an emoji -> 413 too large // after: downscale and compress before upload // convert icon.png -resize 128x128 icon_128.png // oxipng -o3 icon_128.png // typically < 100 KiB // then POST /api/system/addCustomEmoji with file=@icon_128.png
Defensive patterns
Strategy: validation
Validate before calling
// Client-side: check size before upload
const MAX = 10 * 1024 * 1024
fi, err := os.Stat(path)
if err != nil { return err }
if fi.Size() > MAX { return fmt.Errorf("file is %d bytes, max %d", fi.Size(), MAX) } Prevention
- Keep emoji assets under 10 MiB; 256x256 png/webp is usually < 100 KiB.
- For the url path, prefer hosts that report Content-Length so the server-side cap fires.
- Strip EXIF/metadata before upload.
When it happens
Trigger: Uploading an emoji file larger than 10 MiB via the file form field; or providing a url whose server reports Content-Length > 10 MiB. Animated GIFs, high-resolution PNGs, and oversized SVGs are the usual offenders.
Common situations: A full-resolution photo used as an emoji; a multi-megabyte animated GIF; a SVG exported with embedded base64 raster data inflating its size.
Related errors
- custom emoji file must not be empty
- invalid custom emoji image
- unsupported custom emoji image format
- custom emoji name must not be empty
- invalid custom emoji name
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/20fb174ae51e8b5d.
Report an issue: GitHub.