claude-code - 💡(How to fix) Fix query() with image content block via AsyncIterable[dict] prompt → 400 "Could not process image"

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When claude_agent_sdk.query(prompt=<AsyncIterable[dict]>) is given a user message whose content includes an Anthropic image block (base64), the bundled Claude Code CLI subprocess returns 400 "Could not process image" instead of forwarding the image to the Anthropic API. Text-only async-iterable prompts work; the same image block sent directly via anthropic.AsyncAnthropic also works — so the image payload is valid and the failure is specific to the SDK → CLI streaming-input path.

Root Cause

When claude_agent_sdk.query(prompt=<AsyncIterable[dict]>) is given a user message whose content includes an Anthropic image block (base64), the bundled Claude Code CLI subprocess returns 400 "Could not process image" instead of forwarding the image to the Anthropic API. Text-only async-iterable prompts work; the same image block sent directly via anthropic.AsyncAnthropic also works — so the image payload is valid and the failure is specific to the SDK → CLI streaming-input path.

Fix Action

Fix / Workaround

This is the only blocker preventing token-level streaming (TextDelta) for multimodal turns when driving the SDK via its async-iterable prompt interface. The documented workaround is to bypass the SDK CLI path and call anthropic.AsyncAnthropic.messages.stream() directly — which works but is a parallel code path we'd like to retire once this is fixed.

Code Example

import asyncio, base64
import claude_agent_sdk as SDK
from claude_agent_sdk import ClaudeAgentOptions

# 1x1 red PNG
PNG = base64.b64encode(
    b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01"
    b"\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f\x00"
    b"\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82"
).decode()

async def prompt():
    yield {
        "type": "user", "session_id": "", "parent_tool_use_id": None,
        "message": {"role": "user", "content": [
            {"type": "text", "text": "Reply with the single word: PASS"},
            {"type": "image", "source": {
                "type": "base64", "media_type": "image/png", "data": PNG}},
        ]},
    }

async def main():
    async for msg in SDK.query(prompt=prompt(),
                               options=ClaudeAgentOptions(max_turns=1)):
        print(type(msg).__name__, msg)

asyncio.run(main())
RAW_BUFFERClick to expand / collapse

Summary

When claude_agent_sdk.query(prompt=<AsyncIterable[dict]>) is given a user message whose content includes an Anthropic image block (base64), the bundled Claude Code CLI subprocess returns 400 "Could not process image" instead of forwarding the image to the Anthropic API. Text-only async-iterable prompts work; the same image block sent directly via anthropic.AsyncAnthropic also works — so the image payload is valid and the failure is specific to the SDK → CLI streaming-input path.

Environment

  • claude-agent-sdk 0.1.68
  • claude CLI present
  • Python 3.11, Linux
  • Streaming-mode input (prompt is an AsyncIterable[dict]), max_turns=1

Minimal reproduction

import asyncio, base64
import claude_agent_sdk as SDK
from claude_agent_sdk import ClaudeAgentOptions

# 1x1 red PNG
PNG = base64.b64encode(
    b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01"
    b"\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f\x00"
    b"\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82"
).decode()

async def prompt():
    yield {
        "type": "user", "session_id": "", "parent_tool_use_id": None,
        "message": {"role": "user", "content": [
            {"type": "text", "text": "Reply with the single word: PASS"},
            {"type": "image", "source": {
                "type": "base64", "media_type": "image/png", "data": PNG}},
        ]},
    }

async def main():
    async for msg in SDK.query(prompt=prompt(),
                               options=ClaudeAgentOptions(max_turns=1)):
        print(type(msg).__name__, msg)

asyncio.run(main())

Expected

The model receives the image and replies (here, PASS).

Actual

The request fails with 400 "Could not process image". The image block is not forwarded to the Anthropic API by the CLI subprocess.

Impact

This is the only blocker preventing token-level streaming (TextDelta) for multimodal turns when driving the SDK via its async-iterable prompt interface. The documented workaround is to bypass the SDK CLI path and call anthropic.AsyncAnthropic.messages.stream() directly — which works but is a parallel code path we'd like to retire once this is fixed.

Ask

Confirm whether image content blocks are expected to be supported on the AsyncIterable[dict] streaming-input path, and if so, fix the CLI forwarding.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix query() with image content block via AsyncIterable[dict] prompt → 400 "Could not process image"