langchain-ai/langchain · error · ValueError
Unexpected generation type
Error message
Unexpected generation type
What it means
`ValueError` raised in the async message-returning helper (used by `apredict`/`ainvoke` internals): after `agenerate` succeeds, `result.generations[0][0]` is not a `ChatGeneration`. The helper expects chat generations whose `.message` it can return; any other `Generation` subclass (plain `Generation`, `ChatGenerationChunk` misuse in custom results) is rejected.
Source
Thrown at libs/core/langchain_core/language_models/chat_models.py:2315
if item is done:
break
yield item # type: ignore[misc]
async def _call_async(
self,
messages: list[BaseMessage],
stop: list[str] | None = None,
callbacks: Callbacks = None,
**kwargs: Any,
) -> BaseMessage:
result = await self.agenerate(
[messages], stop=stop, callbacks=callbacks, **kwargs
)
generation = result.generations[0][0]
if isinstance(generation, ChatGeneration):
return generation.message
msg = "Unexpected generation type"
raise ValueError(msg)
@property
@abstractmethod
def _llm_type(self) -> str:
"""Return type of chat model."""
@deprecated("1.4.2", alternative="asdict", removal="2.0.0")
@override
def dict(self, **_kwargs: Any) -> builtins.dict[str, Any]:
"""DEPRECATED - use `asdict()` instead.
Return a dictionary representation of the chat model.
"""
return self.asdict()
def asdict(self) -> builtins.dict[str, Any]:
"""Return a dictionary representation of the chat model."""
starter_dict = dict(self._identifying_params)View on GitHub (pinned to e32fa9a52e)
Solutions
- Wrap messages in `ChatGeneration(message=...)`, not `Generation(text=...)`, inside custom `_agenerate`/`_astream` accumulation.
- If you only need text, use the `LLM`/`BaseLLM` hierarchy instead of `BaseChatModel`.
- Inspect `type(result.generations[0][0])` in a debugger to confirm which generation class is being produced.
- Use `ChatResult(generations=[ChatGeneration(message=AIMessage(...))])` as the canonical return shape.
Example fix
# before return ChatResult(generations=[[Generation(text="hi")]]) # after from langchain_core.outputs import ChatGeneration from langchain_core.messages import AIMessage return ChatResult(generations=[[ChatGeneration(message=AIMessage(content="hi"))]])
Defensive patterns
Strategy: type-guard
Validate before calling
result = await model.agenerate([messages])
gen = result.generations[0][0]
if not isinstance(gen, ChatGeneration):
raise TypeError(f"custom model returned {type(gen).__name__}") Type guard
from langchain_core.outputs import ChatGeneration
def is_chat_generation(g: object) -> bool:
return isinstance(g, ChatGeneration) Try / catch
try:
msg = await model.ainvoke(messages)
except ValueError as e:
if "Unexpected generation type" in str(e):
# fix the custom _agenerate to return ChatGeneration, then retry
raise RuntimeError("custom model must return ChatGeneration") from e
raise Prevention
- Always build `ChatResult` with `ChatGeneration` entries in custom models.
- Add a contract unit test for custom `_generate`/`_agenerate` return shapes.
- Don't port `Generation(text=...)` patterns from LLM subclasses into chat models.
When it happens
Trigger: A custom `BaseChatModel` subclass whose `agenerate`/`_agenerate` builds a `ChatResult` containing non-`ChatGeneration` entries (e.g. plain `Generation(text=...)` copied from an LLM implementation), then the caller uses `ainvoke`/`apredict`-style paths.
Common situations: Porting an `LLM` (completion-style) subclass to `BaseChatModel` and reusing `Generation`; building `ChatResult` manually in test fakes with the wrong generation class; mixing v1 and v2 result shapes.
Related errors
- AsyncTextProjection received a non-string final value
- Expected generate to return a ChatResult, but got {type(chat
- DNS resolution failed
- DNS resolution returned no results
- Unable to dispatch an adhoc event without a parent run id.Th
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/2abd0454fe21fca1.
Report an issue: GitHub.