microsoft/autogen · error · ValueError

Message type must be a string, got {type(message_type)}

Error message

Message type must be a string, got {type(message_type)}

What it means

Intended to be raised when data['type'] is not a string (e.g. an int or bytes). Note the guard order in the source: the 'not in self._message_types' check runs first, so any non-string value that isn't a registered key already raises 'Unknown message type' before this branch. In practice this error is nearly unreachable; seeing it means a non-string type value collided with a registry lookup.

Source

Thrown at python/packages/autogen-agentchat/src/autogen_agentchat/messages.py:637

            raise ValueError(f"Message type {message_type} is already registered.")
        if not issubclass(message_type, BaseChatMessage) and not issubclass(message_type, BaseAgentEvent):
            raise ValueError(f"Message type {message_type} must be a subclass of BaseChatMessage or BaseAgentEvent.")
        # Get the class name of the
        class_name = message_type.__name__
        # Check if the class name is already registered.
        # Register the message type.
        self._message_types[class_name] = message_type

    def create(self, data: Mapping[str, Any]) -> BaseAgentEvent | BaseChatMessage:
        """Create a message from a dictionary of JSON-serializable data."""
        # Get the type of the message from the dictionary.
        message_type = data.get("type")
        if message_type is None:
            raise ValueError("Field 'type' is required in the message data to recover the message type.")
        if message_type not in self._message_types:
            raise ValueError(f"Unknown message type: {message_type}")
        if not isinstance(message_type, str):
            raise ValueError(f"Message type must be a string, got {type(message_type)}")

        # Get the class for the message type.
        message_class = self._message_types[message_type]

        # Create an instance of the message class.
        assert issubclass(message_class, BaseChatMessage) or issubclass(message_class, BaseAgentEvent)
        return message_class.load(data)


ChatMessage = Annotated[
    TextMessage | MultiModalMessage | StopMessage | ToolCallSummaryMessage | HandoffMessage,
    Field(discriminator="type"),
]
"""The union type of all built-in concrete subclasses of :class:`BaseChatMessage`.
It does not include :class:`StructuredMessage` types."""

AgentEvent = Annotated[
    ToolCallRequestEvent

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Coerce the field to a string before calling create(): data['type'] = str(data['type']).
  2. Fix the upstream producer so it always writes 'type' as a JSON string.
  3. If you hit this exact message (not 'Unknown message type'), audit any code that mutates the factory's _message_types registry with non-string keys.

Example fix

# before
factory.create({"type": 5, "content": "hi"})

# after
factory.create({"type": "TextMessage", "content": "hi"})
Defensive patterns

Strategy: validation

Validate before calling

if not isinstance(data.get("type"), str):
    data = {**data, "type": str(data.get("type"))}
msg = factory.create(data)

Type guard

def type_is_str(data: Mapping[str, Any]) -> bool:
    return isinstance(data.get("type"), str)

Prevention

When it happens

Trigger: Calling MessageFactory.create() with data['type'] set to a non-string, non-None value (e.g. {'type': 5}) — though most such inputs actually fail earlier with 'Unknown message type' because registry keys are strings.

Common situations: Corrupted or externally produced message payloads where 'type' was encoded as a number or bytes; JSON-decoded data that went through a lossy transform.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/f75b8ad33a00d20b. Report an issue: GitHub.