From b82169fba1c556bacd6efb8a9151364e5993905c Mon Sep 17 00:00:00 2001 From: Wang Qi Date: Tue, 7 Jul 2026 17:00:40 +0800 Subject: [PATCH] Fix: ValueError: Operation on closed image (#16697) --- rag/utils/base64_image.py | 54 +++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/rag/utils/base64_image.py b/rag/utils/base64_image.py index 494fe89cf..6fca7c19c 100644 --- a/rag/utils/base64_image.py +++ b/rag/utils/base64_image.py @@ -40,44 +40,40 @@ async def image2id(d: dict, storage_put_func: partial, objname: str, bucket: str del d["image"] return + image = d.pop("image") + def encode_image(): - with BytesIO() as buf: - img, close_after = open_image_for_processing(d["image"], allow_bytes=False) + img, close_after = open_image_for_processing(image, allow_bytes=False) - if isinstance(img, bytes): - buf.write(img) - buf.seek(0) - return buf.getvalue() + if isinstance(img, bytes): + return bytes(img) - if not isinstance(img, Image.Image): - return None + if not isinstance(img, Image.Image): + return None + owned_images = [img] if close_after else [] + try: + img.load() if img.mode in ("RGBA", "P"): - orig_img = img - img = img.convert("RGB") - if close_after: - try: - orig_img.close() - except Exception: - pass + converted = img.convert("RGB") + owned_images.append(converted) + img = converted - try: + with BytesIO() as buf: img.save(buf, format="JPEG") - buf.seek(0) return buf.getvalue() - except OSError as e: - logging.warning(f"Saving image exception: {e}") - return None - finally: - if close_after: - try: - img.close() - except Exception: - pass + except (OSError, ValueError) as e: + logging.warning(f"Saving image exception: {e}") + return None + finally: + for owned_img in owned_images: + try: + owned_img.close() + except Exception: + pass jpeg_binary = await thread_pool_exec(encode_image) if jpeg_binary is None: - del d["image"] return async with minio_limiter: @@ -85,10 +81,6 @@ async def image2id(d: dict, storage_put_func: partial, objname: str, bucket: str d["img_id"] = f"{bucket}-{objname}" - if not isinstance(d["image"], bytes): - d["image"].close() - del d["image"] - def parse_storage_composite_id(composite_id: str) -> tuple[str, str] | None: """Split a ``{bucket}-{object_key}`` storage ID on the first hyphen only.