{"record":{"id":"31c73025a4a510fb","repo":"zylon-ai/private-gpt","slug":"no-output-object-was-generated","errorCode":null,"errorMessage":"No output object was generated","messagePattern":"No output object was generated","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/workflows/others/summary.py","lineNumber":127,"sourceCode":"        \"\"\"Run the summarization workflow and return formatted content blocks.\"\"\"\n        handler: WorkflowHandler | None = None\n        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","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/workflows/others/summary.py#L109-L145","documentation":"Raised by SummarizeWorkflow.run_summary after the workflow finished: the caller passed output_cls (a Pydantic model for structured output) but the resulting SummarizeResultEvent.output_obj is None or falsy. The workflow step that should have populated output_obj (from a PydanticResponse) either never matched a PydanticResponse or the model returned an empty object. It is a post-execution integrity check, not an LLM transport error.","triggerScenarios":"Calling run_summary(..., output_cls=SomeBaseModel) where the underlying query engine returns a plain Response/StreamingResponse instead of PydanticResponse, or returns a PydanticResponse whose .response payload is empty/falsy. Also occurs when output_cls is not correctly propagated to the query engine so SummarizeResultEvent(summary=...) is emitted without output_obj.","commonSituations":"Structured-output summarization where the LLM output failed to parse into the Pydantic model; retriever returning zero nodes so the response object is empty; switching an existing summary pipeline to output_cls without enabling structured output on the LLM/query engine.","solutions":["Check what the workflow step returned: log the SummarizeResultEvent — if summary is set but output_obj is None, the query engine did not produce a PydanticResponse for your output_cls.","Verify output_cls is a valid pydantic BaseModel and is passed through SummarizeInputEvent to the query engine's response_mode='structured'/'pydantic' configuration.","If the LLM returned unparseable content, tighten the output_cls schema (simpler field types, defaults) or add prompt instructions demanding JSON matching the schema.","If empty results are expected (e.g. empty corpus), supply empty_response_fallback and handle it before requesting structured output."],"exampleFix":"// before\nresult_blocks = await workflow.run_summary(prompt=p, output_cls=MySummary)\n\n// after\nresult: SummarizeResultEvent = await workflow.run(start_event=SummarizeInputEvent(..., output_cls=MySummary))\nif output_cls and result.output_obj is None:\n    # engine produced a plain summary, not structured output\n    result_blocks = [TextBlock(text=result.summary or \"\")]\nelse:\n    result_blocks = [TextBlock(text=result.output_obj.model_dump_json())]","handlingStrategy":"validation","validationCode":"handler = workflow.run(start_event=SummarizeInputEvent(..., output_cls=output_cls))\nresult = await handler\nif output_cls and not result.output_obj:\n    raise_or_handle(\"engine produced no structured output; falling back to summary\")","typeGuard":"def has_output_obj(ev: SummarizeResultEvent) -> bool:\n    return isinstance(ev.output_obj, BaseModel)","tryCatchPattern":"try:\n    blocks = await wf.run_summary(prompt=p, output_cls=Cls)\nexcept ValueError as e:\n    if 'No output object' in str(e):\n        blocks = await wf.run_summary(prompt=p)  # retry without structured output","preventionTips":["Always pair output_cls with engine configuration that produces PydanticResponse","Log SummarizeResultEvent fields in dev builds to catch empty structured results early","Add integration tests asserting output_obj is populated for each output_cls"],"tags":["llm","structured-output","pydantic","summarization","workflow"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}