{"record":{"id":"973b90f52ec64ab9","repo":"BerriAI/litellm","slug":"error-parsing-openrouter-response-e","errorCode":null,"errorMessage":"Error parsing OpenRouter response: {e}","messagePattern":"Error parsing OpenRouter response: (.+?)","errorType":"http","errorClass":"OpenRouterException","httpStatus":null,"severity":"error","filePath":"litellm/llms/openrouter/image_edit/transformation.py","lineNumber":205,"sourceCode":"\n        # Add mapped optional params (image_config, n, etc.)\n        for key, value in image_edit_optional_request_params.items():\n            if key not in (\"model\", \"messages\", \"modalities\"):\n                request_body[key] = value\n\n        empty_files: Final = cast(RequestFiles, [])\n        return request_body, empty_files\n\n    def transform_image_edit_response(\n        self,\n        model: str,\n        raw_response: httpx.Response,\n        logging_obj: LiteLLMLoggingObj,\n    ) -> ImageResponse:\n        try:\n            response_json: Final = raw_response.json()\n        except Exception as e:\n            raise OpenRouterException(\n                message=f\"Error parsing OpenRouter response: {e}\",\n                status_code=raw_response.status_code,\n                headers=raw_response.headers,\n            )\n\n        model_response: Final = ImageResponse()\n        model_response.data = []\n\n        try:\n            choices: Final = response_json.get(\"choices\", [])\n\n            for choice in choices:\n                message = choice.get(\"message\", {})\n                images = message.get(\"images\", [])\n\n                for image_data in images:\n                    image_url_obj = image_data.get(\"image_url\", {})\n                    image_url = image_url_obj.get(\"url\")","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/openrouter/image_edit/transformation.py#L187-L223","documentation":"LiteLLM's OpenRouter image-edit handler calls raw_response.json() on the HTTP response before mapping it to an ImageResponse. If the body is not valid JSON (empty body, HTML error page, plain-text gateway error), the parser's exception is wrapped in an OpenRouterException that forwards the real HTTP status code and headers. The underlying json() message is embedded in the exception text.","triggerScenarios":"Calling litellm.image_edit() with an openrouter/* model when OpenRouter (or a proxy in front of it) returns a non-JSON body: an HTML 502/504 page from a gateway, an empty body from a timed-out upstream, a plain-text rate-limit message, or a custom api_base pointing at a service that does not return JSON.","commonSituations":"OpenRouter incidents or rate limits that surface HTML/text error pages; overriding api_base with a misconfigured internal gateway; requesting a model on the image-edit endpoint that upstream providers refuse with a non-JSON error.","solutions":["Catch OpenRouterException and log status_code and headers; reproduce the same request with curl to see the raw body","Verify the model actually supports image editing on OpenRouter and that the model string is prefixed openrouter/","Remove or correct any custom api_base override so requests hit OpenRouter directly","Retry with exponential backoff for transient 5xx/gateway responses","Upgrade litellm to the latest release in case the handler's error path improved"],"exampleFix":"// before\nresp = litellm.image_edit(model=\"openrouter/google/gemini-2.5-flash-image-preview\", image=f, prompt=\"add a hat\")\n\n// after\nfrom litellm.exceptions import OpenRouterException\ntry:\n    resp = litellm.image_edit(model=\"openrouter/google/gemini-2.5-flash-image-preview\", image=f, prompt=\"add a hat\")\nexcept OpenRouterException as e:\n    logger.error(\"image_edit failed status=%s headers=%s msg=%s\", e.status_code, dict(e.headers), e.message)\n    raise","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Wrap litellm.image_edit() in try/except OpenRouterException. Branch on e.status_code: 4xx points to config/model problems, 5xx or a message starting with 'Error parsing' points to gateway/transient issues - log e.headers and the message (it embeds the json() failure) before re-raising or falling back to another image provider.","preventionTips":["Verify the model supports image editing on OpenRouter before shipping","Leave api_base unset unless you control the proxy and it returns JSON","Log status_code and headers on every image_edit failure to speed triage"],"tags":["openrouter","image-edit","json-parsing","http-response","litellm"],"backgroundTag":"invalid-json-response","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}