PrefectHQ/fastmcp · error · ValueError
ImageContent is only supported in user messages for Anthropi
Error message
ImageContent is only supported in user messages for Anthropic
What it means
ValueError from `_convert_to_anthropic_messages` (list-content branch): Anthropic's API only accepts image blocks in user-role messages, so an ImageContent found in an assistant (or other non-user) message is rejected.
Source
Thrown at fastmcp_slim/fastmcp/client/sampling/handlers/anthropic.py:210
] = []
for item in content:
if isinstance(item, ToolUseContent):
content_blocks.append(
ToolUseBlockParam(
type="tool_use",
id=item.id,
name=item.name,
input=item.input,
)
)
elif isinstance(item, TextContent):
content_blocks.append(
TextBlockParam(type="text", text=item.text)
)
elif isinstance(item, ImageContent):
if message.role != "user":
raise ValueError(
"ImageContent is only supported in user messages "
"for Anthropic"
)
content_blocks.append(_image_content_to_anthropic_block(item))
elif isinstance(item, AudioContent):
raise ValueError(
"AudioContent is not supported by the Anthropic API"
)
elif isinstance(item, ToolResultContent):
# Extract text content from the result
result_content: str | list[TextBlockParam] = ""
if item.content:
text_blocks: list[TextBlockParam] = [
TextBlockParam(type="text", text=sub_item.text)
for sub_item in item.content
if isinstance(sub_item, TextContent)
]
if len(text_blocks) == 1:View on GitHub (pinned to 1f02114297)
Solutions
- Move image content into the user message of the exchange
- Drop ImageContent items from non-user messages before invoking the handler
- Rewrite the assistant turn as text describing the image
- Filter/normalize messages before passing the SamplingMessage list
Example fix
// before messages = [SamplingMessage(role="assistant", content=[ImageContent(...)]), ...] // after messages = [SamplingMessage(role="assistant", content=[TextContent(type="text", text="(image shown to user)")]), ...]
Defensive patterns
Strategy: validation
Validate before calling
def strip_nonuser_images(messages):
return [
m if m.role == "user"
else SamplingMessage(role=m.role, content=[b for b in as_list(m.content) if not isinstance(b, ImageContent)])
for m in messages
] Type guard
def images_only_in_user_messages(messages) -> bool:
from mcp.types import ImageContent
return all(
m.role == "user" or not any(isinstance(b, ImageContent) for b in as_list(m.content))
for m in messages
) Prevention
- Never attach ImageContent to assistant messages
- Normalize conversation history roles before sampling
- Move images to the user turn that references them
- Add a message-shape linter/check before provider calls
When it happens
Trigger: A sampling message with role != "user" whose content is a list containing an ImageContent item; typically assistant messages carrying image blocks in the conversation history passed to the Anthropic handler.
Common situations: Replaying conversation histories where images were attached to assistant turns; multi-turn sampling contexts built by middleware that doesn't enforce role constraints.
Related errors
- Unsupported image MIME type for Anthropic: {content.mime_typ
- AudioContent is not supported by the Anthropic API
- Unsupported content type for Anthropic: {type(item).__name__
- Unsupported content type: {type(content)}
- No content in response from Anthropic
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/45a3ec4825d54802.
Report an issue: GitHub.