{"record":{"id":"e490e56440d5847f","repo":"PrefectHQ/fastmcp","slug":"imagecontent-audiocontent-is-only-supported-in-use","errorCode":null,"errorMessage":"ImageContent/AudioContent is only supported in user messages for OpenAI","messagePattern":"ImageContent/AudioContent is only supported in user messages for OpenAI","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/client/sampling/handlers/openai.py","lineNumber":259,"sourceCode":"                        tool_messages.append(\n                            ChatCompletionToolMessageParam(\n                                role=\"tool\",\n                                tool_call_id=item.tool_use_id,\n                                content=content_text,\n                            )\n                        )\n                    else:\n                        raise ValueError(\n                            f\"Unsupported content type for OpenAI: {type(item).__name__}\"\n                        )\n\n                # Add assistant message with tool calls if present\n                # OpenAI requires: assistant (with tool_calls) -> tool messages\n                if tool_calls or content_parts:\n                    if tool_calls:\n                        has_multimodal = len(content_parts) > len(text_parts)\n                        if has_multimodal:\n                            raise ValueError(\n                                \"ImageContent/AudioContent is only supported \"\n                                \"in user messages for OpenAI\"\n                            )\n                        text_str = \"\\n\".join(text_parts) or None\n                        openai_messages.append(\n                            ChatCompletionAssistantMessageParam(\n                                role=\"assistant\",\n                                content=text_str,\n                                tool_calls=tool_calls,\n                            )\n                        )\n                        # Add tool messages AFTER assistant message\n                        openai_messages.extend(tool_messages)\n                    elif content_parts:\n                        if message.role == \"user\":\n                            openai_messages.append(\n                                ChatCompletionUserMessageParam(\n                                    role=\"user\",","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py#L241-L277","documentation":"OpenAI requires assistant messages to be text-only (plus tool_calls). When building an assistant message that includes tool_calls, if any content parts are non-text (image/audio detected by comparing part counts), the handler raises this ValueError.","triggerScenarios":"A sampling message with role='assistant' that has tool_calls AND multimodal content (ImageContent/AudioContent) in its content list, converted during _convert_to_openai_messages.","commonSituations":"Replaying conversation histories where the assistant attached images alongside tool calls; MCP servers that echo rich assistant content; importing histories from providers (e.g. Claude) that allow multimodal assistant turns.","solutions":["Ensure assistant messages with tool_calls contain only TextContent.","Move images/audio into a following user message.","Strip non-text content from assistant messages before sampling.","Use a provider/handler that supports multimodal assistant messages (e.g. Anthropic or google-genai handler)."],"exampleFix":"// before\nSamplingMessage(role='assistant', content=[TextContent(...), ImageContent(...)], tool_calls=[...])\n// after\nSamplingMessage(role='assistant', content=[TextContent(...)], tool_calls=[...])  # image moved to a user message","handlingStrategy":"validation","validationCode":"for m in messages:\n    if m.role == 'assistant' and getattr(m, 'tool_calls', None):\n        if any(getattr(c, 'type', None) != 'text' for c in m.content):\n            raise ValueError('Assistant tool_call messages must be text-only for OpenAI')","typeGuard":"def is_openai_safe_assistant_with_tools(m) -> bool:\n    return not (m.role == 'assistant' and getattr(m, 'tool_calls', None)\n                and any(getattr(c, 'type', None) != 'text' for c in m.content))","tryCatchPattern":"try:\n    result = await client.sample(...)\nexcept ValueError as e:\n    if 'only supported in user messages for OpenAI' in str(e):\n        messages = move_media_to_user_messages(messages)\n        result = await client.sample(messages=messages, ...)\n    else:\n        raise","preventionTips":["Keep assistant turns with tool_calls text-only.","Replay histories from multimodal providers with media relocated to user turns.","Validate history structure before switching sampling providers."],"tags":["openai","sampling","content-conversion","assistant-message"],"backgroundTag":"unsupported-media-type","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}