{"record":{"id":"b012a3235e75a1c8","repo":"siyuan-note/siyuan","slug":"image-model-returned-neither-base64-data-nor-url","errorCode":null,"errorMessage":"image model returned neither base64 data nor URL","messagePattern":"image model returned neither base64 data nor URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/openai.go","lineNumber":915,"sourceCode":"\t\timageRequest.OutputFormat = request.OutputFormat\n\t}\n\trequestCtx, cancel := context.WithTimeout(ctx, adapter.timeout)\n\tdefer cancel()\n\tresponse, err := adapter.client.CreateImage(requestCtx, imageRequest)\n\tif err != nil {\n\t\treturn GeneratedImage{}, err\n\t}\n\tif len(response.Data) == 0 {\n\t\treturn GeneratedImage{}, errors.New(\"image model returned no image\")\n\t}\n\tresult := response.Data[0]\n\tvar data []byte\n\tif result.B64JSON != \"\" {\n\t\tdata, err = base64.StdEncoding.DecodeString(result.B64JSON)\n\t} else if result.URL != \"\" {\n\t\tdata, err = downloadGeneratedImage(requestCtx, result.URL)\n\t} else {\n\t\terr = errors.New(\"image model returned neither base64 data nor URL\")\n\t}\n\tif err != nil {\n\t\treturn GeneratedImage{}, err\n\t}\n\tmimeType, extension, err := ValidateGeneratedImage(data)\n\tif err != nil {\n\t\treturn GeneratedImage{}, err\n\t}\n\treturn GeneratedImage{Data: data, MIMEType: mimeType, Extension: extension, RevisedPrompt: result.RevisedPrompt}, nil\n}\n\nfunc downloadGeneratedImage(ctx context.Context, rawURL string) ([]byte, error) {\n\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","sourceCodeStart":897,"sourceCodeEnd":933,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/openai.go#L897-L933","documentation":"Each item in the image API response is expected to carry either B64JSON (base64-encoded image) or URL (a link to download from). If an item has neither, the adapter cannot obtain image bytes and returns this error instead of producing an empty GeneratedImage. This usually means the provider's response shape changed or a middleware mangled it.","triggerScenarios":"response.Data[0] has both B64JSON == \"\" and URL == \"\" — e.g. provider returns a new field format (partial image data, streaming chunks), or a proxy rewrites the JSON dropping those fields.","commonSituations":"Using a third-party OpenAI-compatible proxy that returns its own response schema; provider API upgrade (gpt-image-1 style responses) with an outdated client library; response item containing only revised_prompt or error details inside Data.","solutions":["Log the raw response JSON to see what fields the provider actually returned","Upgrade github.com/siyuan-note/httpclient/openai (go-sash) client library to one that understands the provider's response format","If using a proxy, configure it to pass through b64_json or url fields unchanged","Pin to a provider/API version whose items always include b64_json or url"],"exampleFix":"// before\nresult := response.Data[0] // B64JSON and URL both empty -> error\n// after\nresult := response.Data[0]\nif result.B64JSON == \"\" && result.URL == \"\" {\n    return GeneratedImage{}, fmt.Errorf(\"image item missing b64_json/url; raw: %s\", rawBody)\n}","handlingStrategy":"type-guard","validationCode":"if item.B64JSON == \"\" && item.URL == \"\" {\n    return errors.New(\"image item lacks both b64_json and url\")\n}","typeGuard":"func hasImagePayload(item openai.ImageResponseDataInner) bool {\n    return item.B64JSON != \"\" || item.URL != \"\"\n}","tryCatchPattern":null,"preventionTips":["Keep the OpenAI client library in sync with the provider's API version","Log raw response bodies when adding new providers/proxies","Prefer providers that always return b64_json for deterministic handling"],"tags":["openai","image-generation","api-response","unexpected-shape"],"backgroundTag":"unexpected-response-shape","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"}