{"record":{"id":"3f7f693708bbe771","repo":"zylon-ai/private-gpt","slug":"expected-output-object-to-be-a-basemodel-got-typ","errorCode":null,"errorMessage":"Expected output object to be a BaseModel, got {type(response)}","messagePattern":"Expected output object to be a BaseModel, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/workflows/others/summary.py","lineNumber":129,"sourceCode":"        try:\n            handler = self.run(\n                start_event=SummarizeInputEvent(\n                    model_id=model_id,\n                    prompt=prompt,\n                    instructions=instructions,\n                    additional_instructions=additional_instructions,\n                    output_cls=output_cls,\n                    empty_response_fallback=empty_response_fallback,\n                )\n            )\n            result: SummarizeResultEvent = await handler\n\n            if output_cls:\n                response = result.output_obj\n                if not response:\n                    raise ValueError(\"No output object was generated\")\n                if not isinstance(response, BaseModel):\n                    raise TypeError(\n                        f\"Expected output object to be a BaseModel, got {type(response)}\"\n                    )\n                return [TextBlock(text=response.model_dump_json())]\n            else:\n                summary = result.summary\n                summary_text = summary if isinstance(summary, str) else None\n\n                if not summary_text:\n                    raise ValueError(\"No summary was generated\")\n\n                return [TextBlock(text=summary_text)]\n        except asyncio.CancelledError as e:\n            if handler:\n                await handler.cancel_run()\n            raise e\n\n    async def _generate_prompt_template(\n        self,","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/workflows/others/summary.py#L111-L147","documentation":"Type-check in run_summary: result.output_obj exists but is not an instance of pydantic BaseModel, so calling model_dump_json() on it would fail. This indicates the workflow returned an object of an unexpected type in the structured-output path — e.g. a dict, a LlamaIndex structured output wrapper, or an object from a different pydantic major version (v1 vs v2).","triggerScenarios":"output_cls requested but the query engine populated output_obj with a dict or other non-BaseModel; mixing pydantic v1 models (llama_index legacy) with a v2 codebase; monkeypatched/mocked SummarizeResultEvent that sets output_obj to a plain object.","commonSituations":"Upgrading llama-index / pydantic major versions where structured output objects changed type; test doubles that bypass pydantic validation; serializing the engine response manually into output_obj.","solutions":["Print type(result.output_obj) to identify the actual type returned by the query engine.","Ensure the pydantic BaseModel used for output_cls and the one imported in summary.py come from the same pydantic major version (v2 everywhere).","If the engine returns a dict, construct the model explicitly: output_cls(**response.response) before setting output_obj.","Align llama-index structured-output configuration so it returns a pydantic v2 model instance."],"exampleFix":"# before\noutput_obj=engine_response.response  # may be a dict\n\n# after\nraw = engine_response.response\noutput_obj = raw if isinstance(raw, BaseModel) else output_cls(**raw)","handlingStrategy":"type-guard","validationCode":"if not isinstance(result.output_obj, BaseModel):\n    result.output_obj = output_cls(**dict(result.output_obj))","typeGuard":"from pydantic import BaseModel\ndef is_pydantic_model(obj: object) -> bool:\n    return isinstance(obj, BaseModel)","tryCatchPattern":"try:\n    blocks = await wf.run_summary(prompt=p, output_cls=Cls)\nexcept TypeError as e:\n    if 'BaseModel' in str(e):\n        # re-wrap dicts into the model and continue\n        ...","preventionTips":["Pin one pydantic major version across the project and llama-index extras","Construct output_obj from output_cls explicitly at the source","Type SummarizeResultEvent.output_obj strictly and let pydantic validate on event creation"],"tags":["pydantic","type-mismatch","structured-output","version-conflict"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}