{"record":{"id":"9460fcbaa3a4f885","repo":"ultralytics/ultralytics","slug":"unable-to-encode-image-source-as-jpeg","errorCode":null,"errorMessage":"Unable to encode image source as JPEG.","messagePattern":"Unable to encode image source as JPEG\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"ultralytics/models/llm.py","lineNumber":174,"sourceCode":"\n    @staticmethod\n    def _image_url(source: Any) -> str:\n        \"\"\"Convert an image URL, path, or array to an OpenAI image URL.\"\"\"\n        if isinstance(source, str) and source.startswith((\"http://\", \"https://\", \"data:image/\")):\n            return source\n        if isinstance(source, (str, Path)):\n            image = cv2.imread(str(source))\n        else:\n            image = (\n                cv2.cvtColor(np.asarray(source.convert(\"RGB\")), cv2.COLOR_RGB2BGR)\n                if isinstance(source, Image.Image)\n                else np.asarray(source)\n            )\n        if image is None:\n            raise ValueError(f\"Unable to read image source {source!r}.\")\n        success, buffer = cv2.imencode(\".jpg\", image)\n        if not success:\n            raise ValueError(\"Unable to encode image source as JPEG.\")\n        return f\"data:image/jpeg;base64,{base64.b64encode(buffer).decode()}\"\n\n    def _get_client(self) -> Any:\n        \"\"\"Create the OpenAI client on first inference.\"\"\"\n        if self.client is None:\n            check_requirements(\"openai>=2.0.0\")\n            from openai import OpenAI\n\n            kwargs = {k: v for k, v in {\"api_key\": self._api_key, \"base_url\": self.base_url}.items() if v is not None}\n            self.client = OpenAI(**kwargs)\n        return self.client\n\n    def _get_async_client(self) -> Any:\n        \"\"\"Create the asynchronous OpenAI client on first inference.\"\"\"\n        if self.async_client is None:\n            check_requirements(\"openai>=2.0.0\")\n            from openai import AsyncOpenAI\n","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/ultralytics/ultralytics/blob/0449ea011cfd6c9a0d50a0bf1043aca5190cd476/ultralytics/models/llm.py#L156-L192","documentation":"ValueError from LLM._to_image_url: the image was successfully loaded (or provided as an array/PIL Image), but cv2.imencode('.jpg', image) returned success=False, meaning OpenAI's required JPEG re-encode of the pixels failed. This is distinct from the read failure: pixels exist, yet encoding them to JPEG is impossible — almost always an unsupported array dtype/shape rather than a bad file.","triggerScenarios":"Passing a numpy array with dtype float32/float64 (imencode needs uint8), an empty 0-byte array, an array with a non-standard channel count (e.g. 4-channel BGRA is accepted, but 2 channels or exotic dtypes are not), or a PIL Image whose np.asarray conversion yields float data.","commonSituations":"Feeding model-preprocessing outputs (normalized float arrays in [0,1] or standardized), passing float masks/gradients meant as images, arrays created via np.zeros((h,w,3), dtype=np.float32).","solutions":["Convert to uint8 before passing: arr = (arr * 255).clip(0,255).astype('uint8') for float data in [0,1].","Ensure the array is HxWx3 BGR (or pass a PIL Image, which the code converts correctly).","Save to a file or PNG/JPEG first and pass the path/URL if in doubt.","Check arr.dtype and arr.shape before the call."],"exampleFix":"# before\nimport numpy as np\nimg = np.random.rand(224, 224, 3).astype(\"float32\")  # float -> imencode fails\nresult = llm(source=img)\n\n# after\nimg = (np.random.rand(224, 224, 3) * 255).astype(\"uint8\")\nresult = llm(source=img)","handlingStrategy":"type-guard","validationCode":"import numpy as np\n\ndef encodable_image_array(arr) -> bool:\n    return (\n        isinstance(arr, np.ndarray)\n        and arr.dtype == np.uint8\n        and arr.ndim in {2, 3}\n        and (arr.ndim == 2 or arr.shape[2] in {1, 3, 4})\n        and arr.size > 0\n    )","typeGuard":"import numpy as np\n\ndef is_uint8_image(arr) -> bool:\n    \"\"\"True for arrays cv2.imencode can encode: non-empty uint8 HxW or HxWx{1,3,4}.\"\"\"\n    return (\n        isinstance(arr, np.ndarray)\n        and arr.dtype == np.uint8\n        and arr.size > 0\n        and (arr.ndim == 2 or (arr.ndim == 3 and arr.shape[2] in {1, 3, 4}))\n    )","tryCatchPattern":null,"preventionTips":["Convert float arrays (model outputs, normalized images) with .clip(0,255).astype('uint8') before passing.","Pass PIL Images directly — the wrapper handles their conversion correctly.","Log arr.dtype/arr.shape in wrappers that forward arbitrary arrays to the LLM."],"tags":["llm","image-encoding","numpy","dtype"],"backgroundTag":null,"analyzedSha":"0449ea011cfd6c9a0d50a0bf1043aca5190cd476","analyzedAt":"2026-08-15T02:34:13.413Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}