run-llama/llama_index · error · ValueError

response must be of type AgentChatResponse or StreamingAgent

Error message

response must be of type AgentChatResponse or StreamingAgentChatResponse

What it means

Pydantic model validator on AgentChatWithStepEndEvent: the optional `response` field must be None, an AgentChatResponse, or a StreamingAgentChatResponse. The whole-dict validator (mode='before') fires when the event is constructed (or deserialized) with any other type — typically a plain string, dict, or a ChatResponse from a raw LLM call. It protects downstream instrumentation consumers that assume agent-chat response semantics.

Source

Thrown at llama-index-core/llama_index/core/instrumentation/events/agent.py:89

    Args:
        response (Optional[AGENT_CHAT_RESPONSE_TYPE]): Agent chat response.

    """

    response: Optional[AGENT_CHAT_RESPONSE_TYPE]

    @model_validator(mode="before")
    @classmethod
    def validate_response(cls: Any, values: Any) -> Any:
        """Validate response."""
        response = values.get("response")
        if response is None:
            pass
        elif not isinstance(response, AgentChatResponse) and not isinstance(
            response, StreamingAgentChatResponse
        ):
            raise ValueError(
                "response must be of type AgentChatResponse or StreamingAgentChatResponse"
            )

        return values

    @field_validator("response", mode="before")
    @classmethod
    def validate_response_type(cls: Any, response: Any) -> Any:
        """Validate response type."""
        if response is None:
            return response
        if not isinstance(response, AgentChatResponse) and not isinstance(
            response, StreamingAgentChatResponse
        ):
            raise ValueError(
                "response must be of type AgentChatResponse or StreamingAgentChatResponse"
            )
        return response

View on GitHub (pinned to afd0fef371)

Solutions

  1. Wrap text in AgentChatResponse before constructing the event: response=AgentChatResponse(response=text).
  2. If you only have an LLM ChatResponse, convert it: AgentChatResponse(response=chat_response.message.content).
  3. For streaming agents, pass the StreamingAgentChatResponse instance itself.

Example fix

# before
from llama_index.core.instrumentation.events.agent import AgentChatWithStepEndEvent
ev = AgentChatWithStepEndEvent(payload=..., response='final answer')  # raises

# after
from llama_index.core.agent.chat.types import AgentChatResponse
ev = AgentChatWithStepEndEvent(payload=..., response=AgentChatResponse(response='final answer'))
Defensive patterns

Strategy: type-guard

Validate before calling

from llama_index.core.agent.chat.types import AgentChatResponse, StreamingAgentChatResponse

def valid_response(r):
    return r is None or isinstance(r, (AgentChatResponse, StreamingAgentChatResponse))

if not valid_response(resp):
    resp = AgentChatResponse(response=str(resp))

Type guard

from llama_index.core.agent.chat.types import AgentChatResponse, StreamingAgentChatResponse
from llama_index.core.instrumentation.events.agent import AGENT_CHAT_RESPONSE_TYPE

def is_agent_chat_response(r: object) -> bool:
    return r is None or isinstance(r, (AgentChatResponse, StreamingAgentChatResponse))

Prevention

When it happens

Trigger: AgentChatWithStepEndEvent(response='done', ...) or Event(...response=chat_response.message.content ...); emitting a custom end event from a workflow step and passing the underlying LLM ChatResponse instead of an AgentChatResponse; deserializing an event payload whose response field was downgraded to a string.

Common situations: Custom agents/workflows that manually dispatch instrumentation events; serializing events to JSON and back (response becomes a dict and fails revalidation); wrapping lower-level LLM APIs that return ChatResponse.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/2f144991597d8a0f. Report an issue: GitHub.