{"record":{"id":"a82fdddfca067a3e","repo":"iflytek/astron-agent","slug":"failed-to-download-image-from-image-url","errorCode":null,"errorMessage":"Failed to download image from {image_url}","messagePattern":"Failed to download image from (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"core/workflow/engine/nodes/base_node.py","lineNumber":1202,"sourceCode":"            # Handle images in history\n            if payload_comp_history and payload_comp_history[0].content_type == \"image\":\n                if self.source == ModelProviderEnum.OPENAI.value:\n                    payload_comp_history.pop(0)\n                if self.source == ModelProviderEnum.XINGHUO.value:\n                    image_models = os.getenv(\n                        \"SPARK_IMAGE_MODEL_DOMAIN\", \"image,imagev3\"\n                    ).split(\",\")\n                    if self.domain in image_models:\n                        if not image_url:\n                            image_url = payload_comp_history[0].content\n                        payload_comp_history.pop(0)\n        # If it's an image understanding model, reserve the first position in array for image\n        if image_url:\n            import requests  # type: ignore\n\n            image_response = requests.get(image_url)\n            if image_response.status_code != 200:\n                raise Exception(f\"Failed to download image from {image_url}\")\n            image_msg = {\n                \"role\": \"user\",\n                \"content\": str(\n                    base64.b64encode(image_response.content).decode(\"utf-8\")\n                ),\n                \"content_type\": \"image\",\n            }\n            await span_context.add_info_events_async({\"image\": str(image_url)})\n        # Don't upload base64\n        if image_msg:\n            await span_context.add_info_events_async(\n                {\"user_message\": json.dumps(user_message[1:], ensure_ascii=False)}\n            )\n        else:\n            await span_context.add_info_events_async(\n                {\"user_message\": json.dumps(user_message, ensure_ascii=False)}\n            )\n        history = [","sourceCodeStart":1184,"sourceCodeEnd":1220,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/workflow/engine/nodes/base_node.py#L1184-L1220","documentation":"Raised in BaseNode._assemble_messages when downloading an image for an image-understanding LLM call fails: requests.get(image_url) returned a non-200 status. This is a plain Exception (not CustomException) because image download is considered an unexpected runtime failure while assembling chat messages.","triggerScenarios":"Calling _chat_with_llm on a node configured with an image_url where the URL returns 404/403/5xx, points to an expired signed URL, or the storage object was deleted.","commonSituations":"Expired MinIO/S3 presigned URLs saved in old workflow runs; private images requiring auth headers that requests.get does not send; mistyped image URLs in node inputs; network/DNS failures inside the cluster.","solutions":["Verify the image URL is reachable (curl it) and re-upload/re-generate a fresh presigned URL if expired","Ensure the image is publicly accessible from the workflow service or pass credentials appropriately","Fix the upstream node/variable that produced the wrong image URL","Add retry with backoff for transient 5xx and pre-validate URLs before executing the node"],"exampleFix":"// before\nimage_url = \"https://minio/bucket/old.png?expires=...\"  // expired\n// after\nimage_url = refresh_presigned_url(\"bucket\", \"old.png\")","handlingStrategy":"try-catch","validationCode":"import requests\ndef image_url_reachable(url: str) -> bool:\n    try:\n        return requests.head(url, timeout=5).status_code == 200\n    except requests.RequestException:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    await node._chat_with_llm(...)\nexcept Exception as e:\n    if str(e).startswith(\"Failed to download image from\"):\n        log.error(\"image unavailable: %s\", e)\n        return fallback_text_only_response()\n    raise","preventionTips":["Use short-lived presigned URLs generated at execution time, not stored ones","Pre-validate image URLs (HEAD request) before running image-understanding nodes","Ensure the workflow service can reach object storage over the network"],"tags":["http","image-download","llm","network"],"backgroundTag":"http-error-response","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}