{"record":{"id":"f0bd157c2370df5d","repo":"PrefectHQ/fastmcp","slug":"imagecontent-is-only-supported-in-user-messages-fo-f0bd15","errorCode":null,"errorMessage":"ImageContent is only supported in user messages for OpenAI","messagePattern":"ImageContent 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":358,"sourceCode":"                    openai_messages.append(\n                        ChatCompletionUserMessageParam(\n                            role=\"user\",\n                            content=content.text,\n                        )\n                    )\n                else:\n                    openai_messages.append(\n                        ChatCompletionAssistantMessageParam(\n                            role=\"assistant\",\n                            content=content.text,\n                        )\n                    )\n                continue\n\n            # Handle ImageContent\n            if isinstance(content, ImageContent):\n                if message.role != \"user\":\n                    raise ValueError(\n                        \"ImageContent is only supported in user messages for OpenAI\"\n                    )\n                openai_messages.append(\n                    ChatCompletionUserMessageParam(\n                        role=\"user\",\n                        content=[_image_content_to_openai_part(content)],\n                    )\n                )\n                continue\n\n            # Handle AudioContent\n            if isinstance(content, AudioContent):\n                if message.role != \"user\":\n                    raise ValueError(\n                        \"AudioContent is only supported in user messages for OpenAI\"\n                    )\n                openai_messages.append(\n                    ChatCompletionUserMessageParam(","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py#L340-L376","documentation":"The OpenAI sampling handler converts MCP sampling messages to OpenAI chat format. OpenAI's chat API only accepts image parts in messages with role 'user'; the handler therefore rejects any ImageContent found in a message whose role is not 'user' (e.g. 'assistant'). It throws a plain ValueError before making any API call.","triggerScenarios":"Calling OpenAI sampling handler with a SamplingMessage whose role is 'assistant' (or any non-'user' role) and whose content list contains an ImageContent item during _convert_to_openai_messages.","commonSituations":"Custom server sampling handlers that echo images back in assistant messages; middleware or proxies that preserve the original message roles but attach screenshots or generated images to assistant turns; hand-built sampling request histories where role assignment is wrong.","solutions":["Move the ImageContent into a SamplingMessage with role='user' before passing the request to the OpenAI sampling handler.","Drop or convert non-user ImageContent items to TextContent (e.g. a placeholder or caption) before invoking the handler.","If images must appear in assistant turns, use a handler/provider that supports them; OpenAI chat completions does not.","Wrap sampling calls in try/except ValueError and rebuild the message list with only user-role images on failure."],"exampleFix":"// before\nSamplingMessage(role='assistant', content=[ImageContent(data=..., mimeType='image/png')])\n// after\nSamplingMessage(role='user', content=[ImageContent(data=..., mimeType='image/png')])","handlingStrategy":"validation","validationCode":"def validate_openai_sampling_messages(messages):\n    for m in messages:\n        if m.role != 'user' and any(isinstance(c, ImageContent) for c in m.content):\n            raise ValueError('ImageContent found in non-user message; move it to a user message')\n    return messages","typeGuard":"def is_user_image_message(m) -> bool:\n    return m.role == 'user' and any(isinstance(c, ImageContent) for c in getattr(m, 'content', []))","tryCatchPattern":"try:\n    result = await openai_handler(messages, params)\nexcept ValueError as e:\n    if 'ImageContent is only supported in user messages' in str(e):\n        messages = [m for m in messages if is_user_image_message(m) or not any(isinstance(c, ImageContent) for c in m.content)]\n        result = await openai_handler(messages, params)\n    else:\n        raise","preventionTips":["Only attach ImageContent to SamplingMessage with role='user'","Add a pre-flight validator over the sampling message list","Keep client/server MCP SDK versions aligned on content types","Test sampling handlers with multimodal histories"],"tags":["openai","sampling","multimodal","validation"],"backgroundTag":"unsupported-content-role","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}