{"record":{"id":"981608f5a6ef4a2c","repo":"siyuan-note/siyuan","slug":"download-generated-image-failed-with-status-d","errorCode":null,"errorMessage":"download generated image failed with status %d","messagePattern":"download generated image failed with status (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/openai.go","lineNumber":946,"sourceCode":"\tparsed, err := url.Parse(rawURL)\n\tif err != nil || parsed.Scheme != \"https\" || parsed.Host == \"\" {\n\t\treturn nil, errors.New(\"generated image URL must use HTTPS\")\n\t}\n\tif err = CheckHostSSRF(parsed.Hostname()); err != nil {\n\t\treturn nil, err\n\t}\n\tclient := generatedImageHTTPClient()\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn nil, fmt.Errorf(\"download generated image failed with status %d\", resp.StatusCode)\n\t}\n\tif resp.ContentLength > maxGeneratedImageBytes {\n\t\treturn nil, errors.New(\"generated image exceeds size limit\")\n\t}\n\tdata, err := io.ReadAll(io.LimitReader(resp.Body, maxGeneratedImageBytes+1))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(data) > maxGeneratedImageBytes {\n\t\treturn nil, errors.New(\"generated image exceeds size limit\")\n\t}\n\treturn data, nil\n}\n\nfunc generatedImageHTTPClient() *http.Client {\n\treturn &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tProxy:       httpclient.ProxyFromEnvironment,","sourceCodeStart":928,"sourceCodeEnd":964,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/openai.go#L928-L964","documentation":"When the image download request completes but the server answers with a status outside 200–299, the adapter wraps the status code into this error via fmt.Errorf. It means the URL was valid and HTTPS-checked but the actual HTTP GET failed (404, 403, 5xx, etc.).","triggerScenarios":"GET on the provider-returned image URL returns 404 (expired signed URL), 403 (missing auth/hotlink protection), 429 (rate limit), or 5xx from the CDN.","commonSituations":"Signed image URLs expire within minutes and the app downloads too late; CDN blocks requests without a browser-like User-Agent; proxy environment (http_proxy) intercepts the request; transient CDN 5xx.","solutions":["Retry the download promptly after generation before the signed URL expires","Check the status code in the error: 404/403 → URL expiry or auth; 429 → back off and retry; 5xx → provider issue, retry later","Remove/fix proxy environment variables (HTTP_PROXY/HTTPS_PROXY) if they break the download","Call the generation API again to obtain a fresh URL"],"exampleFix":"// before\nurl, _ := genImage(ctx, prompt)\ntime.Sleep(10 * time.Minute) // signed URL expired -> 403/404\ndata, err := downloadGeneratedImage(ctx, url)\n// after\nurl, _ := genImage(ctx, prompt)\ndata, err := downloadGeneratedImage(ctx, url) // download immediately","handlingStrategy":"retry","validationCode":"u, err := url.Parse(rawURL)\nif err != nil || u.Scheme != \"https\" { return err } // cheap pre-check before the request","typeGuard":null,"tryCatchPattern":"var sErr *statusErr\nif errors.As(err, &sErr) && (sErr.code == 429 || sErr.code >= 500) {\n    // retry with backoff\n}","preventionTips":["Download the image immediately after generation (signed URLs expire)","Implement exponential backoff for 429/5xx","Check proxy env vars when downloads fail unexpectedly"],"tags":["http","download","image","network"],"backgroundTag":"http-error-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"}