siyuan-note/siyuan · error
download generated image failed with status %d
Error message
download generated image failed with status %d
What it means
Thrown by downloadGeneratedImage (kernel/util/openai.go:799) when the HTTP response status code is outside the 2xx range. It fires after the SSRF and redirect guards pass, so it specifically indicates the remote image host refused or failed the GET.
Source
Thrown at kernel/util/openai.go:799
parsed, err := url.Parse(rawURL)
if err != nil || parsed.Scheme != "https" || parsed.Host == "" {
return nil, errors.New("generated image URL must use HTTPS")
}
if err = CheckHostSSRF(parsed.Hostname()); err != nil {
return nil, err
}
client := generatedImageHTTPClient()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)
if err != nil {
return nil, err
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("download generated image failed with status %d", resp.StatusCode)
}
if resp.ContentLength > maxGeneratedImageBytes {
return nil, errors.New("generated image exceeds size limit")
}
data, err := io.ReadAll(io.LimitReader(resp.Body, maxGeneratedImageBytes+1))
if err != nil {
return nil, err
}
if len(data) > maxGeneratedImageBytes {
return nil, errors.New("generated image exceeds size limit")
}
return data, nil
}
func generatedImageHTTPClient() *http.Client {
return &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,View on GitHub (pinned to 251596fc0d)
Solutions
- Retry the download immediately — most 4xx/5xx from signed CDN URLs are transient.
- If persistently 403, request b64_json instead of URL delivery so there is no TTL window.
- Shorten the gap between CreateImage and the download (avoid long work between them).
- Check provider status and rate limits if 429/5xx repeats.
Example fix
// before
data, err = downloadGeneratedImage(requestCtx, result.URL)
if err != nil { return GeneratedImage{}, err }
// after (bounded retry on transient download failures)
var data []byte
for attempt := 1; attempt <= 3; attempt++ {
data, err = downloadGeneratedImage(requestCtx, result.URL)
if err == nil { break }
logging.LogWarnf("image download attempt %d failed: %s", attempt, err)
if attempt < 3 { time.Sleep(time.Duration(attempt) * time.Second) }
}
if err != nil { return GeneratedImage{}, err } Defensive patterns
Strategy: retry
Validate before calling
// Cannot pre-check a remote status code; pre-flight belongs to retry logic — see tryCatchPattern.
Try / catch
var data []byte
for attempt := 1; attempt <= 3; attempt++ {
var derr error
data, derr = downloadGeneratedImage(ctx, result.URL)
if derr == nil { break }
if strings.Contains(derr.Error(), "failed with status") && attempt < 3 {
time.Sleep(time.Duration(attempt) * time.Second)
continue
}
return GeneratedImage{}, derr
} Prevention
- Minimize the gap between CreateImage and the download — signed URLs expire.
- Default to b64_json for short-TTL providers.
- Watch for 429 in logs and back off the request rate.
When it happens
Trigger: GET against the model-returned URL returns 403 (signed URL expired), 404 (object gone), 429 (rate limited), or 5xx (CDN/provider error). Generated-image URLs from providers like OpenAI are typically short-lived signed links, so 403 after a delay is the classic case.
Common situations: The download started after the signed URL's TTL expired (slow model + slow pipeline); CDN outage; rate-limit burst; provider revoked the URL; redirect chain that ended at an error page.
Related errors
- image model returned no image
- list models HTTP %d
- list models HTTP %d: %s
- generated image is empty
- generated image exceeds size limit
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/981608f5a6ef4a2c.
Report an issue: GitHub.