{"record":{"id":"f282d160a80dcc2f","repo":"run-llama/llama_index","slug":"structuredllm-expected-a-self-output-cls-name-f282d1","errorCode":null,"errorMessage":"StructuredLLM expected a {self.output_cls.__name__} instance from astructured_predict, but got {type(output).__name__}: {output!r}. The underlying LLM failed to produce valid structured output.","messagePattern":"StructuredLLM expected a (.+?) instance from astructured_predict, but got (.+?): (.+?)\\. The underlying LLM failed to produce valid structured output\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/llms/structured_llm.py","lineNumber":126,"sourceCode":"\n    # ===== Async Endpoints =====\n    @llm_chat_callback()\n    async def achat(\n        self,\n        messages: Sequence[ChatMessage],\n        **kwargs: Any,\n    ) -> ChatResponse:\n        # NOTE: we are wrapping existing messages in a ChatPromptTemplate to\n        # make this work with our FunctionCallingProgram, even though\n        # the messages don't technically have any variables (they are already formatted)\n\n        chat_prompt = ChatPromptTemplate(message_templates=messages)\n\n        output = await self.llm.astructured_predict(\n            output_cls=self.output_cls, prompt=chat_prompt, llm_kwargs=kwargs\n        )\n        if not isinstance(output, BaseModel):\n            raise TypeError(\n                f\"StructuredLLM expected a {self.output_cls.__name__} instance \"\n                f\"from astructured_predict, but got {type(output).__name__}: \"\n                f\"{output!r}. The underlying LLM failed to produce valid \"\n                f\"structured output.\"\n            )\n        return ChatResponse(\n            message=ChatMessage(\n                role=MessageRole.ASSISTANT, content=output.model_dump_json()\n            ),\n            raw=output,\n        )\n\n    @llm_chat_callback()\n    async def astream_chat(\n        self,\n        messages: Sequence[ChatMessage],\n        **kwargs: Any,\n    ) -> ChatResponseAsyncGen:","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/llms/structured_llm.py#L108-L144","documentation":"Async counterpart of the StructuredLLM type check: astructured_predict must return a pydantic BaseModel instance; when the underlying LLM's structured output machinery yields anything else (dict, str, None), StructuredLLM.achat raises TypeError, flagging that the model failed to produce valid structured output for output_cls.","triggerScenarios":"Awaiting structured_llm.achat(messages) (or acomplete, which delegates to achat) when the wrapped LLM returns a non-BaseModel from astructured_predict — no function calling, invalid JSON, or output_cls not being a pydantic v2 model.","commonSituations":"Async chat apps using as_structured_llm with local/open-weight models; mixing pydantic v1 schemas with a pydantic v2 llama-index-core; overly complex output schemas the model cannot satisfy.","solutions":["Define output_cls as a pydantic v2 BaseModel.","Switch to a model with reliable native structured output (function calling, JSON mode, or grammar-constrained decoding).","Simplify the schema and add descriptions/defaults to make compliance easier.","Wrap achat in try/except TypeError with one retry; transient parse failures are common."],"exampleFix":"# before\nresp = await structured_llm.achat(msgs)\n# after\nfrom pydantic import BaseModel\nclass Answer(BaseModel):\n    text: str\nstructured_llm = llm.as_structured_llm(Answer)\ntry:\n    resp = await structured_llm.achat(msgs)\nexcept TypeError:\n    resp = await structured_llm.achat(msgs)  # one retry","handlingStrategy":"retry","validationCode":"from pydantic import BaseModel\n\ndef is_valid_output_cls(output_cls) -> bool:\n    return isinstance(output_cls, type) and issubclass(output_cls, BaseModel)","typeGuard":"from pydantic import BaseModel\n\ndef is_pydantic_v2_model(cls) -> bool:\n    return isinstance(cls, type) and issubclass(cls, BaseModel) and hasattr(cls, \"model_validate\")","tryCatchPattern":"for attempt in range(2):\n    try:\n        resp = await structured_llm.achat(messages)\n        break\n    except TypeError as e:\n        if \"StructuredLLM expected\" not in str(e) or attempt == 1:\n            raise","preventionTips":["Use pydantic v2 BaseModel schemas with as_structured_llm.","Choose models with native structured-output support for async structured chat.","Add one bounded retry around achat to absorb transient malformed outputs."],"tags":["llama-index","async","structured-output","pydantic","type-error"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}