langchain-ai/langchain · error · RuntimeError
v2 stream finished without producing a message
Error message
v2 stream finished without producing a message
What it means
`RuntimeError` raised in sync `_generate_with_cache` after driving the v2 protocol-event stream to completion: the stream accumulator's `output_message` was still `None`. The v2 streaming path (native event generator or the `_stream` compat bridge) is expected to assemble at least one message; reaching the end without one is an invariant violation.
Source
Thrown at libs/core/langchain_core/language_models/chat_models.py:1951
**kwargs,
):
stream_accum = ChatModelStream(
message_id=(
f"{LC_ID_PREFIX}-{run_manager.run_id}" if run_manager else None
)
)
assert run_manager is not None # noqa: S101
for _event in self._iter_v2_events(
messages,
run_manager=run_manager,
stream=stream_accum,
stop=stop,
**kwargs,
):
pass
if stream_accum.output_message is None:
msg = "v2 stream finished without producing a message"
raise RuntimeError(msg)
result = ChatResult(
generations=[ChatGeneration(message=stream_accum.output_message)]
)
# If stream is not explicitly set, check if implicitly requested by
# astream_events() or astream_log(). Bail out if _stream not implemented
elif self._should_stream(
async_api=False,
run_manager=run_manager,
**kwargs,
):
chunks: list[ChatGenerationChunk] = []
run_id: str | None = (
f"{LC_ID_PREFIX}-{run_manager.run_id}" if run_manager else None
)
yielded = False
index = -1
index_type = ""
for chunk in self._stream(messages, stop=stop, **kwargs):View on GitHub (pinned to e32fa9a52e)
Solutions
- Ensure the model's `_stream` (or native event generator) emits at least one message-producing chunk/`message_start`-style event.
- Reproduce with v2 streaming disabled (no v2 handlers attached) to confirm the model itself returns a message; if not, fix the model.
- Check for upstream API errors that end the stream early — the error may mask the real cause; inspect the raw stream.
- Upgrade `langchain-core`: v2 bridge regressions have been fixed across releases.
Example fix
# before
def _stream(self, messages, stop=None, **kw):
return
yield # v2 path ends with output_message None
# after
def _stream(self, messages, stop=None, **kw):
yield ChatGenerationChunk(message=AIMessageChunk(content=self._generate(messages, stop=stop).generations[0].message.content)) Defensive patterns
Strategy: validation
Validate before calling
def stream_yields_message(model, messages) -> bool:
for _ in model._stream(messages):
return True
return False Try / catch
try:
result = model.invoke(messages)
except RuntimeError as e:
if "v2 stream finished without producing" in str(e):
# detach v2 handlers / fall back to plain invoke without callbacks
result = model.invoke(messages, callbacks=None)
else:
raise Prevention
- Guarantee custom `_stream` yields at least one chunk for every input path.
- Smoke-test custom models with tracing handlers attached (they can enable v2 streaming).
- Keep langchain-core updated for v2 bridge fixes.
When it happens
Trigger: A v2-opted-in callback handler (`_V2StreamingCallbackHandler`) triggers protocol streaming, but the model's event generator / `_stream` produces no message events — empty streams, streams that only emit non-message events, or a broken compat bridge in a custom subclass.
Common situations: Custom chat models that implement `_stream` but yield nothing for some inputs; providers returning empty completions; LangSmith/tracing handlers that opt into v2 streaming while the model produces zero events.
Related errors
- Stream finished without producing a message
- AsyncTextProjection received a non-string final value
- No generations found in stream.
- SyncTextProjection requires a string delta
- SyncTextProjection requires a string final value
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/a6b23e970edd20c4.
Report an issue: GitHub.