{"record":{"id":"1747c3c6e959d072","repo":"PrefectHQ/fastmcp","slug":"audiocontent-is-only-supported-in-user-messages-fo","errorCode":null,"errorMessage":"AudioContent is only supported in user messages for OpenAI","messagePattern":"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":372,"sourceCode":"\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(\n                        role=\"user\",\n                        content=[_audio_content_to_openai_part(content)],\n                    )\n                )\n                continue\n\n            raise ValueError(f\"Unsupported content type: {type(content)}\")\n\n        return openai_messages\n\n    @staticmethod\n    def _chat_completion_to_create_message_result(\n        chat_completion: ChatCompletion,\n    ) -> CreateMessageResult:","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py#L354-L390","documentation":"Analogous to the image case: OpenAI chat messages only support audio input parts in user messages, so the handler raises ValueError when AudioContent appears in a sampling message with a non-'user' role during conversion.","triggerScenarios":"Passing a SamplingMessage with role='assistant' (or other non-'user' role) containing AudioContent through the OpenAI sampling handler's _convert_to_openai_messages.","commonSituations":"Voice-agent pipelines that place transcribed or raw audio in assistant turns; replayed conversation logs where roles were re-mapped incorrectly; server code that attaches generated audio to assistant messages.","solutions":["Move AudioContent into a SamplingMessage with role='user'.","Replace assistant-role audio with a TextContent transcript before calling the handler.","Use a provider/handler that supports audio in assistant messages if that is a hard requirement.","Catch the ValueError and re-encode the message list with audio only in user turns."],"exampleFix":"// before\nSamplingMessage(role='assistant', content=[AudioContent(data=..., mimeType='audio/wav')])\n// after\nSamplingMessage(role='user', content=[AudioContent(data=..., mimeType='audio/wav')])","handlingStrategy":"validation","validationCode":"def validate_openai_sampling_messages(messages):\n    for m in messages:\n        if m.role != 'user' and any(isinstance(c, AudioContent) for c in m.content):\n            raise ValueError('AudioContent found in non-user message; move it to a user message')\n    return messages","typeGuard":"def is_user_audio_message(m) -> bool:\n    return m.role == 'user' and any(isinstance(c, AudioContent) for c in getattr(m, 'content', []))","tryCatchPattern":"try:\n    result = await openai_handler(messages, params)\nexcept ValueError as e:\n    if 'AudioContent is only supported in user messages' in str(e):\n        messages = [m for m in messages if not (m.role != 'user' and any(isinstance(c, AudioContent) for c in m.content))]\n        result = await openai_handler(messages, params)\n    else:\n        raise","preventionTips":["Place AudioContent only in user-role sampling messages","Convert assistant audio to a text transcript before sampling","Validate message roles before calling the handler","Cover audio flows with handler unit tests"],"tags":["openai","sampling","audio","validation"],"backgroundTag":"unsupported-content-role","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}