siyuan-note/siyuan · error
generated image redirect is not allowed
Error message
generated image redirect is not allowed
What it means
Thrown inside generatedImageHTTPClient's CheckRedirect (kernel/util/openai.go:822) when an HTTP redirect chain either exceeds 2 hops (len(via) >= 3 means this is the 4th request) or a redirect target uses a non-https scheme. It hardens image downloads against redirect-based SSRF and downgrade attacks.
Source
Thrown at kernel/util/openai.go:822
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,
DialContext: generatedImageDialer().DialContext,
},
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 3 || req.URL.Scheme != "https" {
return errors.New("generated image redirect is not allowed")
}
return CheckHostSSRF(req.URL.Hostname())
},
}
}
func generatedImageDialer() *net.Dialer {
return &net.Dialer{
Timeout: 30 * time.Second,
Control: func(_, address string, _ syscall.RawConn) error {
host, _, err := net.SplitHostPort(address)
if err != nil {
return err
}
ip, parseErr := netip.ParseAddr(host)
if parseErr != nil || isUnsafeGeneratedImageIP(ip.Unmap()) {
return errors.New("generated image URL resolved to a private or invalid IP")
}View on GitHub (pinned to 251596fc0d)
Solutions
- Switch the request to b64_json so no URL fetch / redirect occurs.
- If you operate the CDN, flatten the redirect chain and keep every hop on https.
- Verify the returned URL is the final asset URL, not a short-link that bounces.
Example fix
// before // request relies on URL delivery; provider returns multi-hop redirects imageRequest.ResponseFormat = "" // provider picks URL // after (force inline base64 to avoid redirects entirely) imageRequest.ResponseFormat = openai.CreateImageResponseFormatB64JSON
Defensive patterns
Strategy: fallback
Validate before calling
// No client-side pre-check; the strategic move is to request b64_json so no fetch happens
if strings.HasPrefix(strings.ToLower(adapter.model), "dall-e") {
imageRequest.ResponseFormat = openai.CreateImageResponseFormatB64JSON
} Try / catch
data, err := downloadGeneratedImage(ctx, result.URL)
if err != nil && strings.Contains(err.Error(), "redirect is not allowed") {
// switch to inline delivery to bypass redirect handling entirely
imageRequest.ResponseFormat = openai.CreateImageResponseFormatB64JSON
response, rerr := adapter.client.CreateImage(ctx, imageRequest)
// ...handle rerr and continue with b64 path
}
if err != nil { return err } Prevention
- Prefer b64_json for providers whose CDN redirect chains you cannot control.
- Flatten redirect chains on any image host you operate; keep every hop https.
- Treat multi-hop redirects from a model URL as suspicious.
When it happens
Trigger: The image URL redirects more than 3 times; a redirect lands on an http:// URL; a redirect loop forms. The hook is invoked by net/http on every 3xx response.
Common situations: Provider CDN chains through multiple regional redirects; a middleware rewrites a redirect to http; a misconfigured load balancer creates a loop; an attacker-controlled URL tries to bounce through redirects to internal hosts.
Related errors
- generated image URL must use HTTPS
- generated image URL resolved to a private or invalid IP
- ip address [%s] is prohibited
- 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/7ac31172a33e3132.
Report an issue: GitHub.