microsoft/semantic-kernel · error · AgentInvokeException

Messages must be a string or a ChatMessageContent for Bedroc

Error message

Messages must be a string or a ChatMessageContent for BedrockAgent.

What it means

Raised by BedrockAgent.get_response when the messages argument is neither a str nor a ChatMessageContent. Although the type hint allows list[str | ChatMessageContent], the runtime check rejects lists — BedrockAgent expects a single user message per invocation because each invoke_agent call sends one inputText to a stateful session.

Source

Thrown at python/semantic_kernel/agents/bedrock/bedrock_agent.py:288

        arguments: KernelArguments | None = None,
        kernel: "Kernel | None" = None,
        **kwargs,
    ) -> AgentResponseItem[ChatMessageContent]:
        """Get a response from the agent.

        Args:
            messages (str | ChatMessageContent | list[str | ChatMessageContent]): The messages.
            thread (AgentThread, optional): The thread. This is used to maintain the session state in the service.
            agent_alias (str, optional): The agent alias.
            arguments (KernelArguments, optional): The kernel arguments to override the current arguments.
            kernel (Kernel, optional): The kernel to override the current kernel.
            **kwargs: Additional keyword arguments.

        Returns:
            A chat message content with the response.
        """
        if not isinstance(messages, str) and not isinstance(messages, ChatMessageContent):
            raise AgentInvokeException("Messages must be a string or a ChatMessageContent for BedrockAgent.")

        thread = await self._ensure_thread_exists_with_messages(
            messages=messages,
            thread=thread,
            construct_thread=lambda: BedrockAgentThread(bedrock_runtime_client=self.bedrock_runtime_client),
            expected_type=BedrockAgentThread,
        )
        assert thread.id is not None  # nosec

        if arguments is None:
            arguments = KernelArguments(**kwargs)
        else:
            arguments.update(kwargs)

        kernel = kernel or self.kernel
        arguments = self._merge_arguments(arguments)

        kwargs.setdefault("streamingConfigurations", {})["streamFinalResponse"] = False

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Pass a single string: await agent.get_response(message="Hello").
  2. Pass a single ChatMessageContent with role=USER: await agent.get_response(message=ChatMessageContent(role=AuthorRole.USER, content="Hello")).
  3. If you have multiple messages, concatenate them into one string or invoke the agent once per message, relying on the Bedrock session to maintain history.
  4. Do not pass None; always supply the user turn.

Example fix

// before
response = await agent.get_response(messages=[msg1, msg2])  # list rejected

// after
response = await agent.get_response(message="Combined: " + msg1.content + msg2.content)
# or invoke sequentially:
for msg in [msg1, msg2]:
    response = await agent.get_response(message=msg, thread=thread)
Defensive patterns

Strategy: type-guard

Validate before calling

from semantic_kernel.contents.chat_message_content import ChatMessageContent

def to_bedrock_message(messages) -> str | ChatMessageContent:
    if isinstance(messages, (str, ChatMessageContent)):
        return messages
    if isinstance(messages, list) and messages:
        # concatenate list into one string
        parts = [m if isinstance(m, str) else m.content for m in messages]
        return "\n".join(parts)
    raise TypeError("BedrockAgent.get_response requires a single str or ChatMessageContent")

Type guard

from semantic_kernel.contents.chat_message_content import ChatMessageContent

def is_valid_bedrock_message(messages) -> bool:
    return isinstance(messages, (str, ChatMessageContent))

Try / catch

from semantic_kernel.exceptions.agent_exceptions import AgentInvokeException

try:
    resp = await agent.get_response(message=msg)
except AgentInvokeException as e:
    if "must be a string or a ChatMessageContent" in str(e):
        resp = await agent.get_response(message=str(msg))  # coerce
    else:
        raise

Prevention

When it happens

Trigger: Triggered in get_response when isinstance(messages, str) and isinstance(messages, ChatMessageContent) are both False — e.g. passing a list of messages, None (when messages param is omitted and defaults), a dict, or any other type.

Common situations: Passing a list of messages like get_response(messages=[msg1, msg2]); passing None explicitly; passing a plain dict or a ChatHistory object; migrating from an agent API that accepts lists (e.g. ChatCompletionAgent) without converting to a single message.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/8e419d8bd0308ace. Report an issue: GitHub.