{"record":{"id":"7f9697b0c2a85c42","repo":"siyuan-note/siyuan","slug":"download-custom-emoji-failed-with-status-d","errorCode":null,"errorMessage":"download custom emoji failed with status %d","messagePattern":"download custom emoji failed with status (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/api/system.go","lineNumber":348,"sourceCode":"\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 {\n\t\treturn nil, \"\", fmt.Errorf(\"custom emoji file must not be empty\")\n\t}\n\n\traster := true","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/api/system.go#L330-L366","documentation":"downloadCustomEmojiData fetches a custom emoji image over HTTP and requires a 200 OK response. Any other status code (404, 403, 500, redirects that end in error, etc.) aborts the download with this error. It protects callers from writing error pages or empty responses to disk as emoji files.","triggerScenarios":"The URL passed to the custom emoji download API (readCustomEmojiData flow) resolves to a server that answers with a non-200 HTTP status: missing file on the remote host, expired/hotlink-protected CDN link, or a proxy returning 403/502.","commonSituations":"Emoji URL points to a deleted GitHub repo path or renamed branch; corporate proxy blocks the request; rate-limited CDN returns 429; user pasted a webpage URL instead of a direct image URL.","solutions":["Verify the URL is reachable and returns 200 (curl -I the URL)","Check whether the remote host requires auth or blocks hotlinking; use a URL that serves the raw image","If behind a proxy, fix proxy/auth settings so the request succeeds","Retry later if the status is 429 or 5xx from a transient upstream"],"exampleFix":"// before\nresp := util.NewCustomReqClient().R().Get(url)\n// after (check status before consuming)\nif resp.StatusCode() != 200 {\n    return fmt.Errorf(\"emoji URL returned %d; use a direct image URL\", resp.StatusCode())\n}","handlingStrategy":"validation","validationCode":"const resp = await fetch(url, {method: \"HEAD\"});\nif (!resp.ok) throw new Error(`emoji URL returned ${resp.status}; use a direct image URL`);","typeGuard":null,"tryCatchPattern":"try {\n  const data = await downloadEmoji(url);\n} catch (e) {\n  if (String(e).includes(\"failed with status\")) {\n    notifyUser(\"The emoji URL is unreachable or returned an error page; check the URL\");\n  }\n}","preventionTips":["Verify URLs return 200 with a HEAD request before registering","Use direct raw-image URLs (e.g. raw.githubusercontent) not webpage links","Avoid hosts with hotlink protection or aggressive rate limits"],"tags":["http","network","download"],"backgroundTag":"http-non-200-response","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"}