{"record":{"id":"df43eb163c411d5f","repo":"siyuan-note/siyuan","slug":"encode-image-failed","errorCode":null,"errorMessage":"encode image failed: ","messagePattern":"encode image failed: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/openai.go","lineNumber":758,"sourceCode":"\tbounds := decoded.Bounds()\n\tneedsResize := maxEdge > 0 && (bounds.Dx() > maxEdge || bounds.Dy() > maxEdge)\n\tif !needsResize && bounds.Dx() == config.Width && bounds.Dy() == config.Height && mimeType != \"image/gif\" {\n\t\treturn PreparedImage{\n\t\t\tData:       data,\n\t\t\tMIMEType:   mimeType,\n\t\t\tWidth:      bounds.Dx(),\n\t\t\tHeight:     bounds.Dy(),\n\t\t\tSourceSize: len(data),\n\t\t}, nil\n\t}\n\tif needsResize {\n\t\tdecoded = imaging.Fit(decoded, maxEdge, maxEdge, imaging.Lanczos)\n\t}\n\tbounds = decoded.Bounds()\n\tif mimeType == \"image/png\" || mimeType == \"image/webp\" {\n\t\tvar output bytes.Buffer\n\t\tif err = png.Encode(&output, decoded); err != nil {\n\t\t\treturn PreparedImage{}, errors.New(\"encode image failed: \" + err.Error())\n\t\t}\n\t\tif maxBytes <= 0 || output.Len() <= maxBytes {\n\t\t\treturn PreparedImage{\n\t\t\t\tData:       output.Bytes(),\n\t\t\t\tMIMEType:   \"image/png\",\n\t\t\t\tWidth:      bounds.Dx(),\n\t\t\t\tHeight:     bounds.Dy(),\n\t\t\t\tSourceSize: len(data),\n\t\t\t}, nil\n\t\t}\n\t}\n\tvar output bytes.Buffer\n\tif err = jpeg.Encode(&output, decoded, &jpeg.Options{Quality: 92}); err != nil {\n\t\treturn PreparedImage{}, errors.New(\"encode image failed: \" + err.Error())\n\t}\n\tif maxBytes > 0 && output.Len() > maxBytes {\n\t\treturn PreparedImage{}, fmt.Errorf(\"prepared image exceeds size limit: %d bytes\", maxBytes)\n\t}","sourceCodeStart":740,"sourceCodeEnd":776,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/util/openai.go#L740-L776","documentation":"Thrown by util.PrepareModelImage (kernel/util/openai.go:758) when re-encoding a decoded/resized PNG or WebP back to PNG fails (png.Encode). This is an internal late-stage failure: by this point the image decoded and was optionally resized, so failure is almost always resource exhaustion (OOM on huge canvases) rather than input format. The stdlib encode error is appended.","triggerScenarios":"Near-limit images (tens of megapixels) on memory-constrained kernels (Docker/WSL limits); concurrent PrepareModelImage calls multiplying peak memory; pathological image content inflating encode buffers.","commonSituations":"Docker desktop kernels with low memory ceilings processing large scans; several multimodal requests in parallel; 32-bit or ARM hosts with tight address space.","solutions":["Reduce peak memory: lower maxPixels and maxEdge so decode+encode buffers stay small","Serialize image preparation (worker pool of 1-2) instead of parallel calls","Raise the container/host memory limit if this is a deployment constraint","Patch PrepareModelImage so a failed PNG encode falls through to the JPEG path instead of returning"],"exampleFix":"// before (library: kernel/util/openai.go)\nif err = png.Encode(&output, decoded); err != nil {\n    return PreparedImage{}, errors.New(\"encode image failed: \" + err.Error())\n}\n\n// after\nif err = png.Encode(&output, decoded); err != nil {\n    // PNG 编码失败时回退到 JPEG 编码，避免整张图片直接失败\n    output.Reset()\n} else if maxBytes <= 0 || output.Len() <= maxBytes {\n    return PreparedImage{Data: output.Bytes(), MIMEType: \"image/png\", Width: bounds.Dx(), Height: bounds.Dy(), SourceSize: len(data)}, nil\n}","handlingStrategy":"fallback","validationCode":"// Estimate peak memory before preparing: decoded RGBA needs W*H*4 bytes\nif cfg, _, e := image.DecodeConfig(bytes.NewReader(data)); e == nil {\n    if int64(cfg.Width)*int64(cfg.Height)*4 > memBudget {\n        data = downscaleFirst(data) // reduce before calling PrepareModelImage\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.HasPrefix(err.Error(), \"encode image failed:\") {\n    // resource failure: skip the image or retry once with smaller limits, never hammer-retry\n}","preventionTips":["Cap maxPixels/maxEdge well under memory limits (decoded bitmap is W*H*4 bytes)","Serialize image preparation rather than running many in parallel","Monitor kernel memory; encode failures here are usually OOM in disguise"],"tags":["go","image","encode","memory","multimodal"],"backgroundTag":"image-encode-failed","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}