unslothai/unsloth · error · ValueError
unsupported content block type {btype!r} in a user message
Error message
unsupported content block type {btype!r} in a user message What it means
Raised by an Anthropic messages-request validator when a user message's content list contains a block whose type is not in _KNOWN_ANTHROPIC_BLOCK_TYPES, or whose type is not a string at all (the isinstance check also prevents an unhashable type value raising TypeError and escaping as a 500). It converts unsupported/absent block types into a clean 400.
Source
Thrown at studio/backend/models/inference.py:2541
if not isinstance(data, dict):
return data
content = data.get("content")
if data.get("role") == "assistant":
# Coerce only an explicit null (resumed tool-only turn). A missing
# content key stays malformed so the required-field check still 400s.
if "content" in data and content is None:
return {**data, "content": ""}
return data
if isinstance(content, list):
for block in content:
btype = (
block.get("type") if isinstance(block, dict) else getattr(block, "type", None)
)
# Guard the value: a non-string type is unsupported too, and a
# membership test on an unhashable value would raise TypeError
# (escaping as a 500 instead of a clean 400).
if not isinstance(btype, str) or btype not in _KNOWN_ANTHROPIC_BLOCK_TYPES:
raise ValueError(f"unsupported content block type {btype!r} in a user message")
return data
class AnthropicTool(BaseModel):
# User-defined client tools have input_schema; Anthropic-schema client tools
# and server tools use type/name.
type: Optional[str] = None
name: Optional[str] = None
description: Optional[str] = None
input_schema: Optional[dict] = None
model_config = {"extra": "allow"}
class AnthropicMessagesRequest(BaseModel):
model: str = "default"
max_tokens: Optional[int] = None
messages: list[AnthropicMessage]
system: Optional[Union[str, list]] = NoneView on GitHub (pinned to 203007d190)
Solutions
- Restrict user-message blocks to the supported types (text, image, tool_use, tool_result — check _KNOWN_ANTHROPIC_BLOCK_TYPES in the repo).
- Convert documents/PDFs to text blocks client-side before sending.
- Validate every block has a string 'type' key before serialization.
Example fix
# before
content = [{"type": "document", "source": {...}}] # unsupported here
# after
content = [{"type": "text", "text": extracted_document_text}] Defensive patterns
Strategy: validation
Validate before calling
KNOWN = {'text', 'image', 'tool_use', 'tool_result'} # mirror _KNOWN_ANTHROPIC_BLOCK_TYPES
def valid_user_blocks(content) -> bool:
if not isinstance(content, list):
return True
return all(
isinstance(b, dict) and isinstance(b.get('type'), str) and b['type'] in KNOWN
for b in content
) Type guard
def is_supported_block(b) -> bool:
return isinstance(b, dict) and isinstance(b.get('type'), str) and b['type'] in {
'text', 'image', 'tool_use', 'tool_result'
} Prevention
- Check _KNOWN_ANTHROPIC_BLOCK_TYPES in the repo for the exact accepted set
- Convert documents/PDFs to text blocks before sending
- Always emit a string 'type' key on generated blocks
When it happens
Trigger: POST /v1/messages with user content [{"type": "document", ...}], [{"type": 123}], or [{}] (missing type). Sending Anthropic server-tool types the backend has not modeled also triggers it.
Common situations: Porting a client from Anthropic's full API which supports more block types (document, thinking, redacted_thinking, server tools) than this backend models; typos in block type strings; blocks built dynamically where type ends up None or non-string.
Related errors
- known block type handled by its typed model
- Provide either content_base64 or file_ids, not both
- Provide either content_base64 or file_ids
- file_ids must not be empty
- block_id is required when using file_ids
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/6ab9eff11549798a.
Report an issue: GitHub.