agentscope-ai/agentscope · error · ValueError
User message can only contain text blocks or data blocks.
Error message
User message can only contain text blocks or data blocks.
What it means
Msg content validation restricts user-role messages to TextBlock and data blocks only; images, audio, video, tool-use blocks, or any other block type in a user message raise this ValueError. This enforces the role/block-type contract used by formatters and models.
Source
Thrown at src/agentscope/message/_base.py:37
ToolResultBlock,
ToolResultState,
ContentBlock,
ContentBlockTypes,
)
from ..types import ReplyFinishedReason, ErrorInfo
from .._logging import logger
if TYPE_CHECKING:
from ..event import AgentEvent
else:
AgentEvent = Any
def _assert_user_content_blocks(content: Sequence[ContentBlock]) -> None:
"""Assert that the content blocks in user message are valid."""
for block in content:
if block.type not in ["text", "data"]:
raise ValueError(
"User message can only contain text blocks or data blocks.",
)
def _assert_system_content_blocks(
content: Sequence[ContentBlock],
) -> None:
"""Assert that the content blocks in system message are valid."""
for block in content:
if block.type not in ["text"]:
raise ValueError("System message can only contain text blocks.")
def _to_blocks(content: str | list) -> list:
"""Convert a plain string to a single-element TextBlock list."""
if isinstance(content, str):
return [TextBlock(text=content)]
return contentView on GitHub (pinned to e90f1c7592)
Solutions
- Remove non-text/data blocks from user content; move images/media into a tool result or the block type the target model API prescribes for user media
- Check the block's .type values before constructing the Msg (see validation code)
- Upgrade/check docs: newer agentscope versions may prescribe a specific multimodal user-message pattern
Example fix
// before
msg = Msg("user", content=[TextBlock(type="text", text="what is this?"), ImageBlock(type="image", ...)], role="user")
// after
msg = Msg("user", content=[TextBlock(type="text", text="what is this?")], role="user")
# attach media through the supported channel, e.g. a multimodal/tool-result block per docs Defensive patterns
Strategy: type-guard
Validate before calling
allowed = {"text", "data"}
assert all(b.type in allowed for b in user_blocks), f"bad user block: {[b.type for b in user_blocks]}" Type guard
def is_valid_user_content(blocks) -> bool:
return all(b.type in ("text", "data") for b in blocks) Try / catch
try:
Msg("user", role="user", content=blocks)
except ValueError as e:
if "text blocks or data blocks" in str(e):
blocks = [b for b in blocks if b.type in ("text", "data")] Prevention
- Build role-specific block factories so user content is validated at creation
- Run validate_role_content on assembled histories before sending
- Keep media in the message channels the model API actually supports
When it happens
Trigger: Msg("user", role="user", content=[TextBlock(...), ImageBlock(...)]) — any block whose type is not "text" or "data" inside a user message; also converting third-party message payloads (e.g. multimodal OpenAI content) to Msg without filtering.
Common situations: Trying to send an image directly in a user message instead of via the API's expected mechanism (e.g. a dedicated multimodal message type or tool result); assembling messages programmatically without role-specific validation; porting chat histories from other frameworks.
Related errors
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/a2291647affb1814.
Report an issue: GitHub.