{"record":{"id":"1fd3ea8eb9a0ff8d","repo":"siyuan-note/siyuan","slug":"download-custom-emoji-failed-w","errorCode":null,"errorMessage":"download custom emoji failed: %w","messagePattern":"download custom emoji failed: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/api/system.go","lineNumber":344,"sourceCode":"\t\treturn io.ReadAll(io.LimitReader(file, maxCustomEmojiSize+1))\n\t}\n\n\trawURL := strings.TrimSpace(request.URL)\n\tif rawURL == \"\" {\n\t\treturn nil, fmt.Errorf(\"field [file] or [url] must not be empty\")\n\t}\n\treturn downloadCustomEmojiData(rawURL)\n}\n\nfunc downloadCustomEmojiData(rawURL string) ([]byte, error) {\n\tparsedURL, err := url.Parse(rawURL)\n\tif err != nil || (parsedURL.Scheme != \"http\" && parsedURL.Scheme != \"https\") || parsedURL.Host == \"\" {\n\t\treturn nil, fmt.Errorf(\"invalid custom emoji URL\")\n\t}\n\n\tresponse, err := util.NewCustomReqClient().R().Get(parsedURL.String())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"download custom emoji failed: %w\", err)\n\t}\n\tdefer response.Body.Close()\n\tif response.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"download custom emoji failed with status %d\", response.StatusCode)\n\t}\n\tif response.ContentLength > maxCustomEmojiSize {\n\t\treturn nil, fmt.Errorf(\"custom emoji file is too large\")\n\t}\n\n\tdata, err := io.ReadAll(io.LimitReader(response.Body, maxCustomEmojiSize+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read custom emoji response failed: %w\", err)\n\t}\n\treturn data, nil\n}\n\nfunc normalizeCustomEmojiData(data []byte) (normalized []byte, ext string, err error) {\n\tif len(data) == 0 {","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/api/system.go#L326-L362","documentation":"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).","triggerScenarios":"Target host unreachable or DNS-unresolvable, server rejects the connection, TLS certificate errors, network offline, or request timeout during emoji download.","commonSituations":"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.","solutions":["Open the emoji URL in a browser to confirm it is reachable from your machine","Check DNS/proxy/firewall settings; configure proxy environment variables if the kernel is behind one","Use a URL on a reachable, trusted HTTPS host (e.g. re-upload the image elsewhere)","Retry if the failure was transient (timeout, connection reset)"],"exampleFix":"// before\naddEmoji({ url: \"https://internal-lan/emoji.png\" }) // kernel cannot reach internal host\n// after\naddEmoji({ url: \"https://cdn.example.com/emoji.png\" }) // publicly reachable host","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await addEmoji({ url });\n} catch (e) {\n  if (String(e).includes(\"download custom emoji failed\")) {\n    console.error(\"Network error fetching emoji; check host reachability/proxy\", e);\n  }\n}","preventionTips":["Prefer publicly reachable HTTPS hosts for emoji assets","Verify the URL loads in a browser on the same machine as the kernel","Configure proxy environment variables when running behind a corporate proxy","Retry once on transient transport failures"],"tags":["network","http","download","emoji"],"backgroundTag":"http-request-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}