microsoft/autogen · error · ValueError

model_client.model_info must be provided when max_retries_on

Error message

model_client.model_info must be provided when max_retries_on_error > 0

What it means

CodeExecutorAgent validates on construction that when max_retries_on_error > 0 a model_client with a populated model_info is available, because retries re-validate failed output against the expected structured format and need model capabilities metadata.

Source

Thrown at python/packages/autogen-agentchat/src/autogen_agentchat/agents/_code_executor_agent.py:493

        self._model_client = None
        if model_client is not None:
            self._model_client = model_client

        if model_context is not None:
            self._model_context = model_context
        else:
            self._model_context = UnboundedChatCompletionContext()

        self._system_messaages: List[SystemMessage] = []
        if system_message is None:
            self._system_messages = []
        else:
            self._system_messages = [SystemMessage(content=system_message)]

        if self._max_retries_on_error > 0:
            if not self._model_client or not self._model_client.model_info:
                raise ValueError("model_client.model_info must be provided when max_retries_on_error > 0")
            if not self._model_client.model_info["structured_output"]:
                raise ValueError("Specified model_client doesn't support structured output mode.")

    @property
    def produced_message_types(self) -> Sequence[type[BaseChatMessage]]:
        """The types of messages that the code executor agent produces."""
        return (TextMessage,)

    @property
    def model_context(self) -> ChatCompletionContext:
        """
        The model context in use by the agent.
        """
        return self._model_context

    async def on_messages(self, messages: Sequence[BaseChatMessage], cancellation_token: CancellationToken) -> Response:
        async for message in self.on_messages_stream(messages, cancellation_token):
            if isinstance(message, Response):

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Remove or zero out max_retries_on_error (it is only needed when you want structured-output retry validation).
  2. Provide a model_client that exposes a filled model_info dict.
  3. If using a custom client, implement the model_info property returning a valid ModelInfo dict.

Example fix

// before
agent = CodeExecutorAgent(
    name="coder",
    code_executor=executor,
    model_client=None,
    max_retries_on_error=2,
)

// after
agent = CodeExecutorAgent(
    name="coder",
    code_executor=executor,
    model_client=None,
)
Defensive patterns

Strategy: validation

Validate before calling

if max_retries_on_error > 0:
    assert model_client is not None, "retries require a model_client"
    assert getattr(model_client, "model_info", None), "retries require model_client.model_info"

agent = CodeExecutorAgent(name="coder", code_executor=exec_,
                          model_client=model_client,
                          max_retries_on_error=max_retries_on_error)

Type guard

def supports_retry_validation(client) -> bool:
    return client is not None and bool(getattr(client, "model_info", None))

Prevention

When it happens

Trigger: Constructing CodeExecutorAgent(max_retries_on_error=2, model_client=None) or with a model client whose model_info is None (common with custom/test clients that skip model_info).

Common situations: Copying retry settings from AssistantAgent examples into a CodeExecutorAgent configured without a model client; custom ChatCompletionClient stubs that return None for model_info.

Related errors


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